diff --git a/.agent/naming-audit/_SUMMARY.md b/.agent/naming-audit/_SUMMARY.md new file mode 100644 index 00000000..b8d2065f --- /dev/null +++ b/.agent/naming-audit/_SUMMARY.md @@ -0,0 +1,677 @@ +# Cross-Package Naming Audit — Executive Summary + +**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:** 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 +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 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. + +--- + +## 1. Top cross-cutting themes + +Ranked by approximate package incidence. Each theme is a generator-level +defect — one template change fixes most of the 77 active packages. + +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) | 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. 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`. +- `EndpointInfo` → `Endpoint` (in `warehouses`, brand mismatch — see Theme 3). +- `SchemaInfo` → `Schema`. +- `CredentialInfo` → `Credential`. +- `MetastoreInfo` → `Metastore`. +- `CatalogInfo` → `Catalog`. +- `RegisteredModelInfo`, `ModelVersionInfo`, `RegisteredModelAliasInfo`, + `TableInfo`, `FunctionInfo`, `ConnectionInfo`, `VolumeInfo`. + +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 +isn't a request/response, drop `Info`.) Same for redundant `Options`/`Spec` +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 — 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: + +- `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 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 `*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: + +- **`*CustomerFacing*` qualifier survives in `networking`** — 40+ + identifiers (`CustomerFacingIngressNetworkPolicy`, + `CustomerFacingVpcEndpointUseCase`, etc.) in active source. Not yet + scanned as findings. +- **`*Proto` suffix** active in a handful of identifiers: + `TriggerStateProto` (`jobs`), `DatabricksServiceExceptionProto`, + `DatabricksServiceExceptionWithDetailsProto` (`apps`). +- **`*Service*` mid-position infix.** `ServiceErrorCode` / `ServiceError` + in `statementexecution`. +- **`*Handler` suffix.** `listCleanRoomNotebookTaskRunsHandler` / + `listCleanRoomNotebookTaskRunsHandlerIter` in `cleanrooms/client.ts`. +- **`*V2*` mid-position.** `RunLifecycleStateV2` (jobs). + +**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. + +--- + +## 2. Cross-package duplication & 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 + +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 | + +`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) + +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 export a class literally named `Client` and a type literally +named `Secret`. + +### 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 (consolidated) + +`accessmanagement` is the consolidated umbrella for object permissions, +permission levels, rule sets, and workspace assignments in a single import +path. + +### 2.5 Tokens + +| Package | What it really is | +|---|---| +| `tokens` | User-self PAT management | +| `tokenmanagement` | Admin-of-others PAT management | + +Both export `Client`, both export request types named identically. 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.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.10 Cluster compute (overlapping warehouses) + +- `warehouses` exposes SQL Warehouses (formerly "SQL Endpoints"); the + TS types still spell `Endpoint*` (e.g. `EndpointInfo`, `EndpointState`). +- `vectorsearch` 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`, and other heavily-nested +types covering the same wire object. + +### 2.12 Features + +| Package | What it really is | +|---|---| +| `features` | Feature definitions | +| `featurestore` | Online stores / publishing | + +The materialized-features surface is folded into `features` +(`MaterializedFeature` types live there). + +### 2.13 Budget policy + +| Package | What it really is | +|---|---| +| `budgetpolicy` | `/api/2.0/accounts/{accountId}/budget-policies` | + +The `budgetpolicy` package stands alone. + +### 2.14 Workspace + +The remaining audited package in this space is: + +| Package | What it really is | +|---|---| +| `workspacebindings` | Securable-to-workspace bindings | + +The workspace filesystem surface (notebooks/folders/files) is not part of +the public-filtered SDK. + +### 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 (consolidated) + +A single `oauth` package covers both Custom and Published app integrations +as well as the published-app catalog. + +### 2.17 Statement / Query / Command execution + +The execution surfaces are: + +| Package | What it really is | +|---|---| +| `statementexecution` | Ad-hoc SQL on a SQL Warehouse | +| `commandexecution` | Python/SQL/Scala/R via Clusters REPL | +| `queries` | Saved-query CRUD | +| `queryhistory` | Read-only query history list | + +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) + +The account-tier 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 | + +Residual `*CustomerFacing*` qualifiers in `networking` are not yet flagged +but match generator rule §8.2. + +### 2.19 Other notable overlaps + +- `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 | `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` | 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 | 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 | 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. | +| `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 inventory — resolved (reference only) + +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 | +|---|---|---| +| **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 `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. 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. | +| **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 in `accessmanagement`. | +| **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). | + +**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 findings + +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. | 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 | +| 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 | `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 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). The column sums to +**479** (the 77 per-package totals add up to 479 exactly). + +| # | Package | Findings | Top theme | +|---|---|---|---| +| 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 + +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 and is out of the current naming-audit corpus. +Retained here as a follow-up note rather than an open finding. + +--- + +## 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 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 + +**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. + +**Illustrative example:** `listCatalogsIter` in `catalogs/v1/client.ts` +(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 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; 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 +(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. + +**Remaining instances on the public surface (~8/77 packages):** + +- `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` + (`ServiceErrorCode` / `ServiceError`). +- `*Handler` suffix in `cleanrooms/client.ts` on + `listCleanRoomNotebookTaskRunsHandler` and its `*Iter` companion. +- Mid-position `V` in `jobs` (`RunLifecycleStateV2`). + +**Illustrative example:** +`CreateNetworkConnectivityConfigPublicRequest` → +`CreateNetworkConnectivityConfigRequest`. + +--- + +## Appendix: Categories (from the per-package audits) + +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 rubric is scoped as follows: + +- **Category 15 "Generic field names losing meaning"** and **Category 19 + "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. +- **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. +- **Category 3 "Acronym casing"** is resolved. +- The **generic top-level `Client` class-name** finding (a Category 1 / + 12 sub-case) is resolved — the generator emits `Client` names. + +The most-cited categories on the type-level surface across all 77 active +audits: + +| # | Category | Surviving on type level | +|---|---|---| +| 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 new file mode 100644 index 00000000..d7046520 --- /dev/null +++ b/.agent/naming-audit/abacpolicies.md @@ -0,0 +1,24 @@ +# Naming Audit: abacpolicies + +**Path:** `packages/uc/abacpolicies/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | + +## High severity + +### 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: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`. +- **Rationale:** Type names should be nouns; the verb form misleads. `ColumnMatcher` makes `matchColumns: ColumnMatcher[]` clearly read as "the matchers". diff --git a/.agent/naming-audit/accessmanagement.md b/.agent/naming-audit/accessmanagement.md new file mode 100644 index 00000000..5651725d --- /dev/null +++ b/.agent/naming-audit/accessmanagement.md @@ -0,0 +1,187 @@ +# Naming Audit: accessmanagement + +**Path:** `packages/accessmanagement/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 11 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 5 | +| Low | 2 | +| Observation | 1 | + +--- + +## High severity + +### 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 + 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. + +### 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 + `Authorization`) is a Go-style abbreviation that does not match the rest + of the package, which spells out `permission` and `permissionLevel` in + full. +- **Category:** Proto-architectural leak (`Request` prefix on a domain + enum), cryptic abbreviation (`Authz`). +- **Suggested name:** `AuthorizationIdentity` (or simply + `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. + +### 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 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 `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 + 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. + +--- + +## Medium severity + +### 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 + 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`. 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. + +### 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 + 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. + +### 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 + 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. + +### 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. +- **Category:** Singular/plural mismatch; generic `Description` suffix. +- **Suggested name:** `PermissionLevelDescription` or + `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:271` +- **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. + +--- + +## Low severity + +### 9. `updateObjectPermissions` uses HTTP PATCH; method name implies replace — `src/v1/client.ts:519,536` +- **Why weird:** Method `updateObjectPermissions` issues HTTP `PATCH` + (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. +- **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. + +### 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` + (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. 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 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. diff --git a/.agent/naming-audit/alerts.md b/.agent/naming-audit/alerts.md new file mode 100644 index 00000000..b11acb9c --- /dev/null +++ b/.agent/naming-audit/alerts.md @@ -0,0 +1,85 @@ +# Naming Audit: alerts + +**Path:** `packages/alerts/src/{v1,v2}/` +**Versions audited:** v1, v2 +**Total weird names flagged:** 6 + +## Summary table + +| # | Severity | Version | Location | Name | Category | +|---|----------|---------|----------|------|----------| +| 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 | 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:9-21` + +```ts +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:175-188` + +```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). + +## Medium severity + +### 3. `trashAlert` — inconsistent action verb (both) + +**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. */ +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`). + +### 4. `TrashAlertRequest` — same as 3, in the type layer (both) + +**Location:** `src/v1/model.ts:199-201`; `src/v2/model.ts:238-242` + +Same verb inconsistency at the type layer. + +### 5. `CronSchedule` — generic name in a single-domain package (v2) + +**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 + +### 6. `LifecycleState` — missing domain prefix (v1) + +**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 new file mode 100644 index 00000000..c25cc5cd --- /dev/null +++ b/.agent/naming-audit/apps.md @@ -0,0 +1,127 @@ +# Naming Audit: `@databricks/sdk-apps` (v1) + +**Package:** `apps` (`packages/apps/src/v1/`) +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `index.ts`, `transport.ts` + +## Summary + +| Severity | Count | +| -------- | ----- | +| Medium | 6 | +| Low | 2 | +| Observation | 2 | +| **Total** | **10** | + +--- + +## Medium-severity findings + +### M1. `EnvVar` — too short +- **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 + 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. + +### M2. `AsyncUpdateAppRequest.appName` carrying a redundant nesting +- **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: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: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 + 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. + +### M4. `Operation.result` carries `error` and `response` arms +- **File:** `model.ts:1413-1424` +- **Category:** Vague/generic (1) +- **Issue:** The `response` arm holds `Record` — a totally + 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: ... | + {$case: 'response'; response: TResponse}`. Or split into + `SpaceCreateOperation`, `SpaceDeleteOperation`, etc. Today the field name + promises nothing. + +### M5. Method name verb inconsistency: `asyncUpdateApp` is verb-prefixed but `updateSpace` returns an `Operation` too +- **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 + 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. + +### M6. `createSpaceOperation`, `deleteSpaceOperation`, `updateSpaceOperation` — `*Operation` suffix is confusing alongside the `Operation` type +- **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 + 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. `appFieldMask(...paths)` and `spaceFieldMask(...paths)` — global helpers +- **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 + schema. Suggests the API is incomplete. +- **Suggestion:** Either expose helpers for every entity with a field-mask + schema, or none. + +### L2. `getSpaceOperation` (method) vs `GetOperationRequest` +- **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. +- **Suggestion:** Either `getOperation` (matching `GetOperationRequest`) or + `GetSpaceOperationRequest` (matching the method name). The current pairing + is asymmetric. + +--- + +## Observations (not necessarily problems) + +### 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`, + `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. + +### 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`. diff --git a/.agent/naming-audit/artifactallowlists.md b/.agent/naming-audit/artifactallowlists.md new file mode 100644 index 00000000..70b68808 --- /dev/null +++ b/.agent/naming-audit/artifactallowlists.md @@ -0,0 +1,69 @@ +# Naming Audit: `artifactallowlists` (v1) + +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 | +| **Total** | **3** | + +--- + +## High Severity + +### H1. `SetArtifactAllowlistRequest` carries server-derived fields on a request type + +- **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 + timestamps/identities and are also present on `ArtifactAllowlistInfo`. +- **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. + +--- + +## Medium Severity + +### M1. `ArtifactAllowlistInfo` — redundant `Info` suffix + +- **File / line:** `src/v1/model.ts:29`. +- **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. `ArtifactMatcher_MatchType` — proto-style nested enum with underscore leak + +- **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 + `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. diff --git a/.agent/naming-audit/authentication.md b/.agent/naming-audit/authentication.md new file mode 100644 index 00000000..ac3a0c6e --- /dev/null +++ b/.agent/naming-audit/authentication.md @@ -0,0 +1,41 @@ +# Naming Audit: authentication + +**Path:** `packages/authentication/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Total weird names flagged:** 1 + +## Summary table + +| Severity | Count | +| --- | --- | +| High | 1 | +| **Total** | **1** | + +--- + +## High severity (must fix) + +### 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 + 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. diff --git a/.agent/naming-audit/budgetpolicy.md b/.agent/naming-audit/budgetpolicy.md new file mode 100644 index 00000000..9cab4ddd --- /dev/null +++ b/.agent/naming-audit/budgetpolicy.md @@ -0,0 +1,33 @@ +# Naming Audit: budgetpolicy + +**Path:** `packages/budgetpolicy/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 2 | + +## High severity + +### 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). +- **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 + +### 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`. +- **Rationale:** `Spec` adds no information. A name that says what the type *describes* (sort options / sort order) is more direct. + +### 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 `_`. diff --git a/.agent/naming-audit/budgets.md b/.agent/naming-audit/budgets.md new file mode 100644 index 00000000..606a85f3 --- /dev/null +++ b/.agent/naming-audit/budgets.md @@ -0,0 +1,158 @@ +# 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/index.ts` + +--- + +## Findings + +### 1. Vague / generic names + +#### F1.1 — `ActionConfiguration` / `actionConfigurationId` / `actionType` (HIGH) +- **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 + 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 F2.1 and F2.2). If the type *must* keep the + "Config" word, `BudgetAlertActionConfig` is shorter and clearer. + +--- + +### 2. Overly verbose + +#### 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 F2.2 this + collapses naming significantly. + +#### F2.2 — `CreateBudgetConfigurationRequest`, + `GetBudgetConfigurationRequest`, + `UpdateBudgetConfigurationRequest`, + `DeleteBudgetConfigurationRequest`, + `ListBudgetConfigurationsRequest` (HIGH) +- **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 + patterns: `client.budgets.create(req: CreateBudgetRequest)`. +- **Suggestion:** Drop the `Configuration` token from request types: + `CreateBudgetRequest`, `GetBudgetRequest`, `UpdateBudgetRequest`, + `DeleteBudgetRequest`, `ListBudgetsRequest`. + +--- + +## Summary table + +| # | Category | Findings | +| - | --------------------------------------- | -------- | +| 1 | Vague / generic | 1 | +| 2 | Overly verbose | 2 | +| — | Proto / architectural leaks | 6 | + +--- + +## Proto / Architectural Leaks + +### 1. `BudgetConfiguration` — model.ts:71 + +- **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` / `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`, `AlertQuantityType`, + `AlertTimePeriod`, `AlertTriggerType`. +- **Rationale:** Drop `Configuration` — it's a proto-message-name + artifact. + +### 3. `ActionConfiguration` / `ActionConfigurationType` — model.ts:47, 7 + +- **Why:** Repeated `Configuration` proto suffix on the action domain. +- **Category:** Proto leak — repeated `Config`/`Configuration` suffix. +- **Suggested:** `Action`, `ActionType`. +- **Rationale:** `Configuration` adds no semantic value here. + +### 4. `BudgetConfigurationFilter` / + `BudgetConfigurationFilter_Clause` / + `BudgetConfigurationFilter_TagClause` / + `BudgetConfigurationFilter_WorkspaceIdClause` / + `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 + 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:119, 193 + +- **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), 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:139, 153, 163, + 175, 213 + +- **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. diff --git a/.agent/naming-audit/catalogs.md b/.agent/naming-audit/catalogs.md new file mode 100644 index 00000000..4dcfe8c9 --- /dev/null +++ b/.agent/naming-audit/catalogs.md @@ -0,0 +1,67 @@ +# Naming Audit: `catalogs` package (v1) + +**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. Overly verbose + +#### 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 +the flag). + +--- + +### 2. Redundant suffixes + +#### 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`). + +#### 2.2 `Flag` suffix on `EffectivePredictiveOptimizationFlag` +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: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 +`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`. + +--- + +### 4. Field contradicting type domain + +#### 4.1 `CreateCatalogRequest` contains read-only output fields +`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, +`provisioningInfo`, `fullName`, `securableType`, +`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`. + +--- + +### 5. Proto-architectural leaks + +#### 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` + 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. diff --git a/.agent/naming-audit/cleanrooms.md b/.agent/naming-audit/cleanrooms.md new file mode 100644 index 00000000..f868fcea --- /dev/null +++ b/.agent/naming-audit/cleanrooms.md @@ -0,0 +1,36 @@ +# Naming Audit: `cleanrooms` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/cleanrooms/` +**Files audited:** `src/v1/model.ts`, `src/v1/client.ts`, `src/v1/index.ts` +**Auditor:** Naming audit pass — TypeScript port of Databricks Go SDK. + +--- + +## Summary + +- **Total findings:** 2 + +--- + +## 1. Proto / Architectural Leaks + +### 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 + `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. + +### 1.2 `listCleanRoomNotebookTaskRunsHandlerIter` — client.ts:716 +- **Why:** Same stray `Handler` infix in the async-iterator companion to + §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 §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 new file mode 100644 index 00000000..a56a5abb --- /dev/null +++ b/.agent/naming-audit/clusterlibraries.md @@ -0,0 +1,85 @@ +# Naming Audit: `clusterlibraries` (v2) + +Path: `/home/parth.bansal/sdk-js/packages/clusterlibraries/` +Files audited: `src/v2/model.ts`, `src/v2/client.ts`, `src/v2/index.ts` + +--- + +## 1. Misleading names + +### 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: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 + 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 §5. + +--- + +## 2. Overly verbose names + +### 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` + or `ListClusterStatusesRequest` would suffice. +- Severity: medium. + +--- + +## 3. Redundant suffixes + +### 3.1 `LibraryFullStatus` — `model.ts:126` +- "Full" is a vestigial qualifier with no counterpart. See §1.1. +- Severity: medium. + +--- + +## 4. Singular/plural mismatches + +### 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. + +--- + +## 5. Verb-tense inconsistency + +### 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: + `listAllClusterStatuses` (or `getAllClusterStatuses`) and + `getClusterStatus`. See §1.2 and §6. +- Severity: high (consistency of the verb-prefix is a Java/TS SDK convention + that consumers rely on). + +--- + +## 6. Inconsistent action verbs + +### 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`). +- Severity: medium (see §5.1). + +--- + +## 7. Type-suffix tautology + +### 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`. +- Severity: low. diff --git a/.agent/naming-audit/clusterpolicies.md b/.agent/naming-audit/clusterpolicies.md new file mode 100644 index 00000000..bb1d8147 --- /dev/null +++ b/.agent/naming-audit/clusterpolicies.md @@ -0,0 +1,43 @@ +# 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/index.ts` + +--- + +## Summary + +| Severity | Count | +| --------- | ----- | +| High | 0 | +| Medium | 3 | +| Low | 0 | +| **Total** | **3** | + +Total weird names flagged: 3. + +--- + +## Medium + +### 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 +`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. + +### 2. `PythonPyPiLibrary` (`model.ts:257`) + +Type-suffix tautology. Same as finding 1. Could be `PyPISpec`. + +### 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 new file mode 100644 index 00000000..8ddad309 --- /dev/null +++ b/.agent/naming-audit/clusters.md @@ -0,0 +1,39 @@ +# Naming Audit: clusters + +**Path:** `packages/clusters/src/v2/` +**Versions audited:** v2 +**Total weird names flagged:** 4 + +## Summary +| Severity | Count | +| --- | --- | +| Medium | 3 | +| Low | 1 | + +## Medium severity + +### 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: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: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`). +- **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 + +### 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). +- **Rationale:** Matches sibling naming (`autoscale: Autoscale`). diff --git a/.agent/naming-audit/commandexecution.md b/.agent/naming-audit/commandexecution.md new file mode 100644 index 00000000..42c3806a --- /dev/null +++ b/.agent/naming-audit/commandexecution.md @@ -0,0 +1,114 @@ +# 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`. + +--- + +## Summary of Findings + +| # | 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 | 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-style member key in `model.ts:22-67`. +**Issue:** TS identifier convention is PascalCase for type-namespace +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 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 const CommandStatus = { + CommandStatusUnspecified: 'COMMAND_STATUS_UNSPECIFIED', + Cancelled: 'Cancelled', + Cancelling: 'Cancelling', + Error: 'Error', + Finished: 'Finished', + Queued: 'Queued', + Running: 'Running', +} as const; +``` + +--- + +### Finding 2 — High — Cat 16 (Field contradicts type domain) & Cat 9 (Plural mismatch) +**Location:** `src/v2/model.ts:130-157` +```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). + +--- + +### Finding 3 — Medium — Cat 7 (Overly verbose) +**Location:** `src/v2/model.ts:113, 125` +```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 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. +**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 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 (`create()`) returns immediately after +the context create call; the *waiter* polls a different endpoint +(`getContextStatus`) for terminal state. +**Proposed:** `CreateContextWaiter` or `ContextWaiter` (parallel to the +target endpoint). + +--- + +### Finding 6 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:373` +**Issue:** `CancelWaiter` waits for *command* cancellation. +**Proposed:** `CancelCommandWaiter`. + +--- + +### Finding 7 — Medium — Cat 6 (Misleading name) +**Location:** `src/v2/client.ts:524` +**Issue:** `ExecuteWaiter` waits for *command* completion. +**Proposed:** `ExecuteCommandWaiter`. diff --git a/.agent/naming-audit/connections.md b/.agent/naming-audit/connections.md new file mode 100644 index 00000000..8a96f66c --- /dev/null +++ b/.agent/naming-audit/connections.md @@ -0,0 +1,39 @@ +# Naming Audit: connections + +**Path:** `packages/uc/connections/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 4 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 3 | + +## High severity + +### 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`. +- **Rationale:** The domain noun is "connection". Stripping `Info` improves every reference (`connection.connectionType` → `Connection.connectionType`). + +## Medium severity + +### 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: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. `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. diff --git a/.agent/naming-audit/credentials.md b/.agent/naming-audit/credentials.md new file mode 100644 index 00000000..589a9dea --- /dev/null +++ b/.agent/naming-audit/credentials.md @@ -0,0 +1,74 @@ +# Naming Audit: credentials + +**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). +**Total weird names flagged:** 3 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 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. | + +--- + +## High severity (must fix) + +### H1. `Public` infix proto-architectural leak (1 type + 4 methods) + +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 +`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` (797). + +Methods (client.ts): + +- `createCredentialsPublic` (987). +- `deleteCredentialsPublic` (1014). +- `getCredentialsPublic` (1040). +- `listCredentialsPublic` (1066). + +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. + +(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` | +| `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. + +--- + +## Medium severity (worth pushing back on) + +### M1. `R2Credentials` requires Cloudflare product knowledge + +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. diff --git a/.agent/naming-audit/customllms.md b/.agent/naming-audit/customllms.md new file mode 100644 index 00000000..309c4562 --- /dev/null +++ b/.agent/naming-audit/customllms.md @@ -0,0 +1,36 @@ +# Naming Audit: customllms + +**Path:** `packages/customllms/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 1 | +| Low | 1 | + +## High severity + +### 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. + +## Medium severity + +### 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). +- **Rationale:** Method names should reflect the resource the verb operates on. The URL operates on the LLM, not on a specific run. + +## Low severity + +### 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`. diff --git a/.agent/naming-audit/database.md b/.agent/naming-audit/database.md new file mode 100644 index 00000000..d622cef0 --- /dev/null +++ b/.agent/naming-audit/database.md @@ -0,0 +1,69 @@ +# Naming Audit: database + +**Path:** `packages/database/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 9 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | +| Medium | 7 | + +## High severity + +### 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: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. +- **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. + +## Medium severity + +### 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: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: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: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: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: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: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. diff --git a/.agent/naming-audit/dataquality.md b/.agent/naming-audit/dataquality.md new file mode 100644 index 00000000..b9d370e2 --- /dev/null +++ b/.agent/naming-audit/dataquality.md @@ -0,0 +1,60 @@ +# Naming Audit: dataquality + +**Path:** `packages/dataquality/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 7 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 3 | +| Low | 1 | + +## High severity + +### 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: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: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}`. +- **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. + +## Medium severity + +### 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: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: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. +- **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 + +### 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. diff --git a/.agent/naming-audit/disasterrecovery.md b/.agent/naming-audit/disasterrecovery.md new file mode 100644 index 00000000..caaa6b40 --- /dev/null +++ b/.agent/naming-audit/disasterrecovery.md @@ -0,0 +1,52 @@ +# Naming Audit: disasterrecovery + +**Path:** `packages/disasterrecovery/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 5 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | +| Medium | 2 | +| Low | 1 | + +## High severity + +### 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: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. + - `targetPrimaryRegion` — request-only on `failover` action. + 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 + +### 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: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 `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. diff --git a/.agent/naming-audit/entitytagassignments.md b/.agent/naming-audit/entitytagassignments.md new file mode 100644 index 00000000..39bde47d --- /dev/null +++ b/.agent/naming-audit/entitytagassignments.md @@ -0,0 +1,33 @@ +# Naming Audit: entitytagassignments + +**Path:** `packages/uc/entitytagassignments/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | +| Medium | 1 | + +## High severity + +### 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: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. +- **Rationale:** "Required." in a docstring while the type is optional is a generator smell. Honest required-ness should travel through the type. + +## Medium severity + +### 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. diff --git a/.agent/naming-audit/environments.md b/.agent/naming-audit/environments.md new file mode 100644 index 00000000..90fb7295 --- /dev/null +++ b/.agent/naming-audit/environments.md @@ -0,0 +1,30 @@ +# 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` + +**Total weird names flagged:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | + +--- + +## High severity + +### 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: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. +- **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 new file mode 100644 index 00000000..19ee2c69 --- /dev/null +++ b/.agent/naming-audit/experiments.md @@ -0,0 +1,89 @@ +# Naming Audit: experiments + +**Path:** `packages/experiments/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 11 + +## Summary +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 4 | +| Low | 2 | + +## High severity + +### 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: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: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: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: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`. +- **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 + +### 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: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: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`. + +### 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) + - `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. + +## Low severity + +### 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: bigint })`. + +### 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 new file mode 100644 index 00000000..279f0095 --- /dev/null +++ b/.agent/naming-audit/externallineage.md @@ -0,0 +1,27 @@ +# Naming Audit: externallineage + +**Path:** `packages/uc/externallineage/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Low | 1 | + +## High severity + +### 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: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. +- **Rationale:** Type name should reflect the dominant content; current name is misleading. diff --git a/.agent/naming-audit/externallocations.md b/.agent/naming-audit/externallocations.md new file mode 100644 index 00000000..245bf736 --- /dev/null +++ b/.agent/naming-audit/externallocations.md @@ -0,0 +1,49 @@ +# Naming Audit: externallocations + +**Path:** `packages/uc/externallocations/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-uc-externallocations` (workspace package; the +folder is one word `externallocations`, no hyphen, no underscore). +**Total weird names flagged:** 2 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +| --- | ------------------- | -------------- | ---- | -------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 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[]`). | + +--- + +## Medium severity (worth pushing back on) + +### 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 +`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. + +### M2. `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` (3 client method return types). +- `ExternalLocationInfo[]` in `ListExternalLocationsResponse`. +- `AsyncGenerator` in the iter method. + +Renaming to `ExternalLocation` removes ~6 occurrences of dead-weight suffix +across the public surface. diff --git a/.agent/naming-audit/externalmetadata.md b/.agent/naming-audit/externalmetadata.md new file mode 100644 index 00000000..bd74e1a9 --- /dev/null +++ b/.agent/naming-audit/externalmetadata.md @@ -0,0 +1,30 @@ +# Naming Audit: externalmetadata + +**Path:** `packages/uc/externalmetadata/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | + +## High severity + +### 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: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: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. diff --git a/.agent/naming-audit/features.md b/.agent/naming-audit/features.md new file mode 100644 index 00000000..811659b5 --- /dev/null +++ b/.agent/naming-audit/features.md @@ -0,0 +1,155 @@ +# Naming Audit: features + +**Path:** `packages/features/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-features` +**Total weird names flagged:** 11 + +--- + +## Summary table + +| # | 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: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. | + +--- + +## High severity (must fix) + +### H1. 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/...`). + +### H2. The `Feature` type name is overloaded + +The unqualified noun `Feature` is the central type of this package +(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 +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). + +### H3. `Function` interface shadows the JS built-in + +`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 +`no-shadow-restricted-names` and the `globals` rule) flag this. + +Rename `AggregationFnDefinition` or `FeatureFunction` to clear the shadow. + +### H4. Proto-architectural leak: `Outer_Inner` nested names (#7-11) + +Three public identifiers carry the proto-nested `_` underscore +convention straight from the `.proto` IDL into the TS public API: + +- `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:1542, 2572). + +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`). + +--- + +## Medium severity (worth pushing back on) + +### M1. One `FeaturesClient` owning four resource families + +The `FeaturesClient` class is 893 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 per-resource sub-clients (or 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. `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.) diff --git a/.agent/naming-audit/featurestore.md b/.agent/naming-audit/featurestore.md new file mode 100644 index 00000000..37732ac6 --- /dev/null +++ b/.agent/naming-audit/featurestore.md @@ -0,0 +1,70 @@ +# Naming Audit: `featurestore` (v1) + +**Path:** `/home/parth.bansal/sdk-js/packages/featurestore/` +**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`, +`OnlineTableSpec`). +**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). + +--- + +## Findings + +### 1. `PublishSpec` is vague — category 1 (Vague/generic) + +**Symbol:** `PublishSpec` (model.ts:107). + +**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.** + +--- + +### 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 +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. + +--- + +### 3. `PublishSpec_PublishMode` — model.ts:31 + +**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. + +**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. diff --git a/.agent/naming-audit/files.md b/.agent/naming-audit/files.md new file mode 100644 index 00000000..5df1a85e --- /dev/null +++ b/.agent/naming-audit/files.md @@ -0,0 +1,30 @@ +# Naming Audit: files + +**Path:** `packages/files/src/v2/` +**Versions audited:** v2 + +**Total weird names flagged:** 1 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | + +## High severity + +### 1. `CreateRequest` returns a `handle` (not the created file) — `src/v2/model.ts:32-42` + +```ts +export interface CreateRequest { + path?: string | undefined; + overwrite?: boolean | undefined; +} +// Response shape: +// handle?: bigint | 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"). +- **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). diff --git a/.agent/naming-audit/forecasting.md b/.agent/naming-audit/forecasting.md new file mode 100644 index 00000000..8402505b --- /dev/null +++ b/.agent/naming-audit/forecasting.md @@ -0,0 +1,145 @@ +# 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/index.ts` +- `src/v1/transport.ts` +- `src/v1/utils.ts` + +--- + +## Findings + +### 1. Misleading names + +#### 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: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 + `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. + +--- + +### 2. Overly verbose + +#### F2.1 — `ForecastingExperiment` (MEDIUM) +- **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 + `import {ForecastingExperiment} from '@databricks/sdk-forecasting'` + — the `Forecasting` is said twice. +- **Suggestion:** Rename to `Experiment`. The package name carries + 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. + +#### F2.2 — `CreateForecastingExperimentRequest`, + `CreateForecastingExperimentResponse`, + `GetForecastingExperimentRequest` (MEDIUM) +- **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: + `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`. + +#### F2.3 — `CreateForecastingExperimentWaiter` (HIGH) +- **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 + 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), so the flow reads + `const run = await client.createForecastingExperiment(req); + await run.wait();`. + +#### F2.4 — `getForecastingExperiment` / `createForecastingExperiment` + methods (MEDIUM) +- **Where:** `client.ts:105, 119`. +- **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. + +--- + +### 3. Go-style `Waiter` pattern + +#### F3.1 — `Waiter` suffix on `CreateForecastingExperimentWaiter` + (LOW) +- **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 + Go-flavored. +- **Suggestion:** Rename suffix to `Operation` or `Run` (e.g. + `ExperimentRun`). See F2.3. + +--- + +### 4. Reserved-word / built-in collisions + +#### F4.1 — `done` method on `CreateForecastingExperimentWaiter` (MEDIUM) +- **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 + encountering `waiter.done` might first think of iteration. +- **Suggestion:** Rename to `isTerminal()` / `isFinished()` (see + F1.1). + +--- + +### 5. Proto / architectural leaks + +#### 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 + 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). +- **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. + +--- + +## Summary table + +| # | Category | Findings | +| - | --------------------------------------- | -------- | +| 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 new file mode 100644 index 00000000..4dfb2e56 --- /dev/null +++ b/.agent/naming-audit/functions.md @@ -0,0 +1,96 @@ +# Naming Audit: `functions` package (v1) + +**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:** 9 + +--- + +## Findings + +### 1. Misleading names + +#### 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. + +--- + +### 2. Go / Java-style names + +#### 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: {…}}`) +rather than wrapping in `value`. Functional, but visibly Go/proto. + +--- + +### 3. Field contradicting type domain + +#### 3.1 `CreateFunction` contains read-only output fields +`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, `metastoreId`, +`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:396-411). + +--- + +### 4. Proto-architectural-leak naming + +#### 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. +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. + +#### 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 4.1. + +#### 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 4.1. + +#### 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 4.1. + +#### 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. +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 +§2.1; re-flagged here as a proto-architectural leak. + +--- + +## Observations + +### A. `fullNameArg` URL substitution silently allows empty string +(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. diff --git a/.agent/naming-audit/genie.md b/.agent/naming-audit/genie.md new file mode 100644 index 00000000..040523bf --- /dev/null +++ b/.agent/naming-audit/genie.md @@ -0,0 +1,114 @@ +# Naming Audit: genie + +**Path:** `packages/genie/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 16 + +## Summary +| Severity | Count | +| --- | --- | +| High | 6 | +| Medium | 4 | +| Low | 6 | + +## High severity + +### 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: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: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: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: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: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. `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. + +### 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`. + +### 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. + +### 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 + +### 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. + +### 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. + +### 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. + +### 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. + +### 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. + +### 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. diff --git a/.agent/naming-audit/gitcredentials.md b/.agent/naming-audit/gitcredentials.md new file mode 100644 index 00000000..badfc8ea --- /dev/null +++ b/.agent/naming-audit/gitcredentials.md @@ -0,0 +1,72 @@ +# 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). +**Total weird names flagged:** 3 + +--- + +## Summary table + +| # | Name | File | Kind | Severity | Category | Issue (one-liner) | +|---|------|------|------|----------|----------|-------------------| +| 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 | `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. | + +--- + +## High severity (must fix) + +### H1. Plural request-type names + +Four request envelopes act on a single resource but use the plural noun: +`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. + +```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 #1, #2, #3. + +--- + +## Medium severity (worth pushing back on) + +### M1. Plural `*Credentials` envelopes for single-resource operations + +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 + +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 | `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`, +URL `/credentials`), singular for resource ops (`getCredential`, +`createCredential`, URL `/credentials/{id}`). diff --git a/.agent/naming-audit/globalinitscripts.md b/.agent/naming-audit/globalinitscripts.md new file mode 100644 index 00000000..8e78fa5c --- /dev/null +++ b/.agent/naming-audit/globalinitscripts.md @@ -0,0 +1,44 @@ +# 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` + +--- + +## 1. Summary + +| Severity | Count | +| -------- | ----- | +| High | 0 | +| Medium | 3 | +| Low | 0 | +| **Total**| **3** | + +--- + +## 2. Findings by Category + +### 2.1 Overly verbose / Redundant suffixes + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------------------- | -------- | ----- | +| 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-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-01 / G-01. | diff --git a/.agent/naming-audit/instancepools.md b/.agent/naming-audit/instancepools.md new file mode 100644 index 00000000..9b8f6a2a --- /dev/null +++ b/.agent/naming-audit/instancepools.md @@ -0,0 +1,89 @@ +# 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` (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) + +--- + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 3 | +| Medium | 3 | +| Low | 2 | +| **Total** | **8** | + +--- + +## 1. Findings + +### 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 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`. | + +### 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.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. | + +### 1.4 Type-suffix tautology + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| TS-01 | `InstancePoolAndStats` | High | Tautological + Go-style "And"-joiner (G-01). Doubly off. | + +### 1.5 Proto-architectural leaks + +### 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 +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. + +### 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 +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. + +--- + +## 2. Severity totals (recap) + +| Severity | Count | +| ------------ | ----- | +| High | 3 | +| Medium | 3 | +| Low | 2 | +| **Total** | **8** | diff --git a/.agent/naming-audit/instanceprofiles.md b/.agent/naming-audit/instanceprofiles.md new file mode 100644 index 00000000..e21759c6 --- /dev/null +++ b/.agent/naming-audit/instanceprofiles.md @@ -0,0 +1,49 @@ +# 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` + +--- + +## 1. Findings by Category + +### 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. | + +### 1.2 Misleading names — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| 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.3 Inconsistent action verbs — High + +| ID | Symbol | Severity | Issue | +| ----- | ----------------------------------- | -------- | ----- | +| 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. | + +--- + +## 2. Summary + +### 2.1 Findings by severity + +| Severity | Count | +| -------- | ----- | +| High | 5 | +| Medium | 0 | +| Low | 0 | +| Observation | 0 | +| **Total**| **5** | diff --git a/.agent/naming-audit/jobs.md b/.agent/naming-audit/jobs.md new file mode 100644 index 00000000..09cbed4b --- /dev/null +++ b/.agent/naming-audit/jobs.md @@ -0,0 +1,144 @@ +# Naming Audit: `@databricks/sdk-jobs` (v2) + +Path: `packages/jobs/src/v2/` +Versions: v2 +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 | 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: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: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: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: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: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: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: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: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: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: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: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: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 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: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: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: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). +- **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. + +--- + +## Medium + +### 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. + +### M2. `BaseRun.numberInJob` — meaningless field (see H7) +- **Location:** `model.ts:1085`. + +### M3. `RunNowResponse.numberInJob` (see H8). + +### 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`. + +### M5. `PythonPyPiLibrary` — duplicate "Py" prefix +- **Location:** `model.ts:3105`. +- **Category:** Redundant prefixes (#2). +- **Suggestion:** Rename to `PyPiLibrary` (PyPI already means "Python Package Index"). + +### 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 M4. + +### 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`. diff --git a/.agent/naming-audit/keyconfigurations.md b/.agent/naming-audit/keyconfigurations.md new file mode 100644 index 00000000..b8eca376 --- /dev/null +++ b/.agent/naming-audit/keyconfigurations.md @@ -0,0 +1,39 @@ +# Naming Audit: keyconfigurations + +**Path:** `packages/keyconfigurations/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Total weird names flagged:** 1 + +## Summary table + +| Severity | Count | +| --- | --- | +| Medium | 1 | +| **Total** | **1** | + +--- + +## Medium severity (worth pushing back on) + +### 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: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. +- **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; 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`). diff --git a/.agent/naming-audit/knowledgeassistants.md b/.agent/naming-audit/knowledgeassistants.md new file mode 100644 index 00000000..63e72b05 --- /dev/null +++ b/.agent/naming-audit/knowledgeassistants.md @@ -0,0 +1,24 @@ +# Naming Audit: knowledgeassistants + +**Path:** `packages/knowledgeassistants/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | + +## 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: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: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. diff --git a/.agent/naming-audit/lakeview.md b/.agent/naming-audit/lakeview.md new file mode 100644 index 00000000..9721841c --- /dev/null +++ b/.agent/naming-audit/lakeview.md @@ -0,0 +1,123 @@ +# 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:** 6 + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 3 | +| Medium | 3 | + +## Summary table + +| # | Severity | Location | Name | Category | +| -- | ----------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------- | +| 1 | High | package name | `lakeview` | 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 | + +--- + +## 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` — single-value enum with a generic, role-obscuring name + +**Location:** `src/v1/model.ts:7-13` + +```ts +export const DashboardView = { + /** Includes summary metadata from the dashboard. */ + DASHBOARD_VIEW_BASIC: 'DASHBOARD_VIEW_BASIC', +} as const; +export type DashboardView = + | (typeof DashboardView)[keyof typeof DashboardView] + | (string & {}); +``` + +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). + +**Category:** 1 (vague). + +**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. `trashDashboard()` / `TrashDashboardRequest` — verb diverges from the SDK-wide `delete` + +**Location:** `src/v1/client.ts:687` (`trashDashboard`), `src/v1/model.ts:432` (`TrashDashboardRequest`) + +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. + +**Category:** 17 (inconsistent action verb). + +**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 `alerts`, `queries`, and `lakeview` soft-delete endpoints are the only places in the SDK that spell delete as `trash`. + +--- + +## Medium severity + +### 4. `MigrateDashboardRequest` / `migrateDashboard` — vague action verb + +**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. + +**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. + +### 5. `trashDashboard` — soft-delete method without a paired restore (see also #3) + +**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. + +**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. + +### 6. `PublishDashboardRequest` vs `PublishedDashboard` — adjacent names with different roles + +**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`. + +**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. diff --git a/.agent/naming-audit/logdelivery.md b/.agent/naming-audit/logdelivery.md new file mode 100644 index 00000000..64de8bf8 --- /dev/null +++ b/.agent/naming-audit/logdelivery.md @@ -0,0 +1,61 @@ +# 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:** 6 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 2 | +| Low | 1 | + +## High severity + +### 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: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 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: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: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: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: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 `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,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. diff --git a/.agent/naming-audit/marketplaces.md b/.agent/naming-audit/marketplaces.md new file mode 100644 index 00000000..01dff777 --- /dev/null +++ b/.agent/naming-audit/marketplaces.md @@ -0,0 +1,282 @@ +# 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:** 13 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 10 | + +--- + +## High severity + +### 1. `AddExchangeForListingRequest` / `RemoveExchangeForListingRequest` — for-Listing word-order + +**Location:** `src/v1/model.ts:207, 840` + +```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`). +- **Rationale:** Mirror the underlying object (`ExchangeListing`) rather than the verb phrase. + +### 2. `ListingSummary` — 19-field "summary" + +**Location:** `src/v1/model.ts:763-784` + +```ts +export interface ListingSummary { + name?: string | undefined; + subtitle?: string | undefined; + status?: ListingStatus | undefined; + share?: ShareInfo | undefined; + providerRegion?: RegionInfo | undefined; + setting?: ListingSetting | undefined; + createdAt?: bigint | undefined; + createdBy?: string | undefined; + updatedAt?: bigint | undefined; + updatedBy?: string | undefined; + publishedAt?: bigint | undefined; + publishedBy?: string | undefined; + categories?: Category[] | undefined; + listingType?: ListingType | undefined; + createdById?: bigint | undefined; + updatedById?: bigint | undefined; + providerId?: string | undefined; + exchangeIds?: string[] | undefined; + gitRepo?: RepoInfo | undefined; +} +``` + +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 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:427-430` + +```ts +export interface FileParent { + parentId?: string | undefined; + fileParentType?: FileParentType | undefined; +} +``` + +`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:** An id-plus-type-tag pair models a polymorphic parent reference; a discriminated union expresses the same contract with type safety. + +--- + +## Medium severity + +### 4. `Cost` — single-word, ambiguous enum + +**Location:** `src/v1/model.ts:53-57` + +```ts +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 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:60-73` + +```ts +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 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:26-49` + +```ts +export const Category = { + ADVERTISING_AND_MARKETING: 'ADVERTISING_AND_MARKETING', + ... + 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 776). +- **Rationale:** Cross-package collision avoidance and self-documentation. + +### 7. `ContactInfo` — generic suffix on a single-purpose type + +**Location:** `src/v1/model.ts:237-242` + +```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 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:835-838` + +```ts +export interface RegionInfo { + cloud?: string | undefined; + region?: string | undefined; +} +``` + +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 the `*Info` suffix; name the type for the concept it represents. + +### 9. `ShareInfo` — `Info` suffix on a sharing concept + +**Location:** `src/v1/model.ts:882-885` + +```ts +export interface ShareInfo { + name?: string | undefined; + type?: ListingShareType | undefined; +} +``` + +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 #7. + +### 10. `ProviderInfo` — `Info` suffix on the canonical provider type + +**Location:** `src/v1/model.ts:816-833` + +```ts +export interface ProviderInfo { + id?: string | undefined; + name?: string | undefined; + description?: string | undefined; + iconFilePath?: string | undefined; + ... +} +``` + +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. + +### 11. `DataRefreshInfo` — `Info` suffix on an interval type + +**Location:** `src/v1/model.ts:330-333` + +```ts +export interface DataRefreshInfo { + interval?: bigint | undefined; + unit?: DataRefresh | undefined; +} +``` + +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. + +### 12. `FileInfo` — `Info` suffix on the canonical file type + +**Location:** `src/v1/model.ts:412-425` + +```ts +export interface FileInfo { + id?: string | undefined; + marketplaceFileType?: MarketplaceFileType | undefined; + ... +} +``` + +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 #10. + +### 13. `ListingTag` — typed-but-not-typed tags + +**Location:** `src/v1/model.ts:748, 786-791` + +```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). +- **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. diff --git a/.agent/naming-audit/metastores.md b/.agent/naming-audit/metastores.md new file mode 100644 index 00000000..075db493 --- /dev/null +++ b/.agent/naming-audit/metastores.md @@ -0,0 +1,76 @@ +# Naming Audit: `metastores` package (v1) + +**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. + +--- + +## Findings + +### 1. Vague / generic names + +#### 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 +struct delivers. Consider `WorkspaceMetastoreLink` or making the +relationship directional in the name. + +--- + +### 2. Misleading names + +#### 2.1 `MetastoreInfo` (model.ts:369) +"Info" suggests metadata about a metastore separate from the entity +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: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. Rename to signal the +current-workspace scope, as `getCurrentMetastoreAssignment` spells out +"current". + +--- + +### 3. Redundant suffixes + +#### 3.1 `…Info` suffix on `MetastoreInfo` (model.ts:369) +"Info" carries no semantic content. Go-SDK convention; TS would just +say `Metastore`. + +--- + +### 4. Field contradicting type domain + +#### 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 §4.1. + +#### 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`. + +--- + +## Additional / cross-cutting observations + +### 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 +`workspaceId` on `CreateMetastoreAssignmentRequest`, +`DeleteMetastoreAssignmentRequest`, and `UpdateMetastoreAssignmentRequest` +(each field is `bigint | undefined`) lets the bug hide. + +### 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. diff --git a/.agent/naming-audit/modelregistry.md b/.agent/naming-audit/modelregistry.md new file mode 100644 index 00000000..d1eb0b7e --- /dev/null +++ b/.agent/naming-audit/modelregistry.md @@ -0,0 +1,235 @@ +# 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:** 15 + +## Summary +| Severity | Count | +| --- | --- | +| High | 13 | +| Medium | 1 | +| Low | 1 | + +## High severity + +### 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 + 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. `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 + 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. + +### 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. +- **Category:** 1 (vague `Object` suffix), 20 (type-suffix tautology). +- **Suggested name:** `Comment`. +- **Rationale:** `Object` adds nothing; the type is already a TS object. + +### 4. `GetRegisteredModelDatabricksRequest`, `RegisteredModelDatabricks`, + `TransitionModelVersionStageDatabricksRequest`, `ModelVersionDatabricks` — + `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 + 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. + +### 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 + 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` 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. + +### 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 + `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. + +### 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`); `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:** 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:807` +- **Why weird:** Type is `RegistryWebhook` but client methods, paths, + 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`, `CreateWebhookRequest`, + `ListWebhooksRequest`, `UpdateWebhookRequest`, `DeleteWebhookRequest`, + `TestWebhookRequest`. +- **Rationale:** Package name already establishes the registry context. + +### 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 + (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. + +### 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 identifiers referencing a feature-store entry. + +### 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`, + `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 #4. +- **Rationale:** See #4. + +### 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 + 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. + +### 13. `transitionModelVersionStageDatabricks` client method — + `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. + 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 #5). +- **Rationale:** Same as #12 — the infix encodes a generator-side + distinction that callers do not need. + +## Medium severity + +### 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: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). +- **Suggested name:** `listLatestVersionPerStage` or + `listLatestVersionsByStage`. +- **Rationale:** Conveys the per-stage semantics. + +## Low severity + +### 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 + 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. diff --git a/.agent/naming-audit/modelserving.md b/.agent/naming-audit/modelserving.md new file mode 100644 index 00000000..90a556ce --- /dev/null +++ b/.agent/naming-audit/modelserving.md @@ -0,0 +1,78 @@ +# 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*`). 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 | +| --- | --- | +| High | 4 | +| Medium | 4 | +| Low | 1 | + +## High severity + +### 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: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: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: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: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:733-754, 806-827, 879-900, 952-973` +- **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. + +### 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: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. +- **Rationale:** The current shape forces every consumer to write `response.logs.split('\n')`. + +## Low severity + +### 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. diff --git a/.agent/naming-audit/modelservingquery.md b/.agent/naming-audit/modelservingquery.md new file mode 100644 index 00000000..f6c67322 --- /dev/null +++ b/.agent/naming-audit/modelservingquery.md @@ -0,0 +1,111 @@ +# Naming Audit: `modelservingquery` (v1) + +**Package:** `@databricks/sdk-modelservingquery` +**Path:** `/home/parth.bansal/sdk-js/packages/modelservingquery/` +**Version audited:** `v1` + +**Total weird names flagged:** 5 + +--- + +## Summary table + +| # | Severity | Location | Name | Category | +|----|----------|-----------------------------------|--------------------------------------------------------------|----------------------------------------------| +| 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 | 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 | + +--- + +## High severity + +### 1. `V1ResponseChoiceElement` — version segment in type name + empty `Element` suffix + +**Location:** `src/v1/model.ts:187-198` + +**Categories:** 7 (overly verbose), 8 (empty suffix), 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. + +### 2. `EmbeddingsV1ResponseEmbeddingElement` — version leak + empty `Element` suffix + +**Location:** `src/v1/model.ts:72-79` + +**Categories:** 7 (overly verbose), 8 (empty suffix) + +```ts +export interface EmbeddingsV1ResponseEmbeddingElement { + embedding?: number[] | undefined; + index?: number | undefined; + object?: EmbeddingsV1ResponseEmbeddingElementObject | undefined; +} +``` + +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. + +### 3. `ExternalModelUsageElement` — misleading scope + meaningless suffix + +**Location:** `src/v1/model.ts:81-88` + +**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. + +--- + +## Medium severity + +### 4. `query()` — verb-tense / reserved-word feel + +**Location:** `src/v1/client.ts:59-86` + +**Categories:** 13 (verb-tense), 10 (reserved-word collision), 17 (inconsistent action verb) + +```ts +/** Query a serving endpoint */ +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. + +### 5. `ChatMessageRole` enum — redundant `Message` segment + +**Location:** `src/v1/model.ts:17-27` + +**Category:** 8 (redundant segment) + +```ts +/** The role of the message. One of [system, user, 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. diff --git a/.agent/naming-audit/networking.md b/.agent/naming-audit/networking.md new file mode 100644 index 00000000..b7896555 --- /dev/null +++ b/.agent/naming-audit/networking.md @@ -0,0 +1,45 @@ +# 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 | +| --- | --- | +| Medium | 4 | + +## Medium severity + +### 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 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:1298` +- **Why weird:** Same singular/plural mismatch as #1. Sibling list + 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:1310` +- **Why weird:** Same singular/plural mismatch as #1. The list request + 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:1314` +- **Why weird:** Same singular/plural mismatch as #1. The list response + 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 new file mode 100644 index 00000000..015735f1 --- /dev/null +++ b/.agent/naming-audit/notificationdestinations.md @@ -0,0 +1,97 @@ +# 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:** 5 + +## Summary + +| Severity | Count | +| --- | --- | +| High | 3 | +| Low | 1 | +| Observation | 1 | + +## Summary table + +| # | Severity | Location | Name | Category | +|---|----------|----------|------|----------| +| 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:6-15` +- **Code:** + ```ts + 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:17-25` +- **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. +- **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. + +### 3. `GenericWebhookConfig` — "generic" is doing too much work — `src/v1/model.ts:46-59` +- **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. +- **Category:** 1 (vague — "generic" carries no positive information). +- **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.). + +## Low severity + +### 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). +- **Suggested name:** `request`, `response`, `httpRequest`. Cost is trivial. + +## Observations + +### 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 }`). +- **Rationale:** Improvement opportunity. Not strictly a naming issue, hence observation. diff --git a/.agent/naming-audit/pipelines.md b/.agent/naming-audit/pipelines.md new file mode 100644 index 00000000..fedd6e46 --- /dev/null +++ b/.agent/naming-audit/pipelines.md @@ -0,0 +1,147 @@ +# 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 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,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` (135 lines) — re-exports. + +## Summary + +| Severity | Count | Notes | +| ------------ | ----- | ------------------------------------------------------------------------------------------- | +| 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: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: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: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. + +### 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 (`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. + +### H5. `client.events()` method name is too generic +- **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: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: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: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: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: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. + +--- + +## Medium + +### M1. `MaturityLevel.DEPRECATED` reads as a deprecation tag, not a maturity level +- **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: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: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: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: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: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: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: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. + +--- + +## Low + +### L1. `PipelinesS3StorageInfo.enableEncryption` boolean alongside `encryptionType` string — coupled fields not enforced by type system +- **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: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/postgres.md b/.agent/naming-audit/postgres.md new file mode 100644 index 00000000..201232b4 --- /dev/null +++ b/.agent/naming-audit/postgres.md @@ -0,0 +1,46 @@ +# 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), `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:** 5 + +## Summary +| Severity | Count | +| --- | --- | +| Medium | 3 | +| Low | 2 | + +## Medium severity + +### 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: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: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:** 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: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 #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: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 new file mode 100644 index 00000000..03e125bc --- /dev/null +++ b/.agent/naming-audit/queries.md @@ -0,0 +1,183 @@ +# 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:** 11 + +## 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` 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` 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 | + +## High severity + +### 1. `Query` — vague/generic top-level name + +**Location:** `src/v1/model.ts:243-277` + +```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. `ListQueryObjectsResponseQuery` — Go-style + filler word + +**Location:** `src/v1/model.ts:183-217` + +```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). + +### 3. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) + +**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. */ +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`. 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`). + +### 4. `QueryBackedValue` — misleading + +**Location:** `src/v1/model.ts:279-286` + +```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. + +### 5. `EnumValue` — vague/generic top-level name + +**Location:** `src/v1/model.ts:160-167` + +```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. + +## Medium severity + +### 6. `trashQuery` — inconsistent action verb (`trash` vs SDK-wide `delete`) + +**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. */ +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`). + +### 7. `TrashQueryRequest` — same as #6, in the type layer + +**Location:** `src/v1/model.ts:332-334` + +```ts +export interface TrashQueryRequest { + id?: string | undefined; +} +``` + +Same verb inconsistency at the type layer. Carries only `id`. + +### 8. `listVisualizationsForQuery` — overly verbose + +**Location:** `src/v1/client.ts:187-225` + +```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. + +### 9. `Visualization` — vague/generic top-level name + +**Location:** `src/v1/model.ts:380-397` + +```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. + +### 10. `RunAsMode` — verb-as-noun, filler `Mode` + +**Location:** `src/v1/model.ts:28-34` + +```ts +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 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:230-237` + +```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). diff --git a/.agent/naming-audit/queryhistory.md b/.agent/naming-audit/queryhistory.md new file mode 100644 index 00000000..749f814b --- /dev/null +++ b/.agent/naming-audit/queryhistory.md @@ -0,0 +1,37 @@ +# 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:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 1 | +| Low | 1 | + +## High severity + +### 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`. +- **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 + +### 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`. +- **Rationale:** Reflects what the value actually represents. Also fixes the singular/plural smell: `PlansState` (plural noun + singular state) reads oddly; `PlanStorageStatus` is uniformly singular. + +## Low severity + +### 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). +- **Rationale:** Minor. diff --git a/.agent/naming-audit/registeredmodels.md b/.agent/naming-audit/registeredmodels.md new file mode 100644 index 00000000..9568b208 --- /dev/null +++ b/.agent/naming-audit/registeredmodels.md @@ -0,0 +1,119 @@ +# Naming Audit: `registeredmodels` package (v1) + +**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. + +--- + +## Summary + +The `registeredmodels` package exposes twelve UC model-registry operations +(`createRegisteredModel`, `deleteRegisteredModel`, `deleteModelVersion`, +`deleteRegisteredModelAlias`, `getRegisteredModel`, `getModelVersion`, +`getModelVersionByAlias`, `listRegisteredModels`, `listModelVersions`, +`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 issue is extremely heavy +`Create*Request`/`Update*Request` shapes that include server-populated +read-only fields (`createdAt`, `createdBy`, `updatedAt`, `updatedBy`, +`fullName`, `metastoreId`, `storageLocation`, `browseOnly`). + +--- + +## Findings + +### 1. Redundant suffixes + +#### 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 +distinguishing a wire DTO from an in-memory entity in the same file. +TypeScript does not need the distinction. + +--- + +### 2. Go / Java-style names + +#### 2.1 `Info` suffix everywhere +Pure Go-ism (`ServerInfo`, `WorkspaceInfo`, `RegisteredModelInfo`). See §1.1. + +--- + +### 3. Generic field names losing meaning + +#### 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 +descriptive; the problem is that its presence in the create-request +shape is semantically odd. Flagged for shape, not just naming. + +--- + +### 4. Field contradicting type domain + +#### 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`) +- `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 +`UpdateRegisteredModelRequest` (model.ts:373-405): all six are present +plus `name`, `catalogName`, `schemaName`, `storageLocation`, `aliases`, +and `browseOnly` — most of which are not actually updatable. + +#### 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 +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. + +#### 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 +isolation but pollutes the shape. + +--- + +### 5. Type-suffix tautology + +#### 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. + +--- + +## Cross-cutting observations + +### 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 §4. + +--- + +## Recommendations (priority-ordered) + +1. **Remove `Info` suffix** from `RegisteredModelInfo`, `ModelVersionInfo`, + `RegisteredModelAliasInfo`. (§1.1, §5.1) +2. **Strip server-populated fields** from `CreateRegisteredModelRequest`, + `UpdateRegisteredModelRequest`, `UpdateModelVersionRequest` request + shapes. (§4, §A) + +--- diff --git a/.agent/naming-audit/repos.md b/.agent/naming-audit/repos.md new file mode 100644 index 00000000..96488b3f --- /dev/null +++ b/.agent/naming-audit/repos.md @@ -0,0 +1,106 @@ +# Naming Audit: repos + +**Path:** `packages/repos/src/v1/` +**Versions audited:** v1 +**Package name:** `@databricks/sdk-repos` +**Total weird names flagged:** 5 + +--- + +## 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". 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 | `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. | + +--- + +## High severity (must fix) + +### 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`, `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* 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: + +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` 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`). + +--- + +## 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 UpdateRepoRequest { + id?: bigint; + branch?: string; + tag?: string; + sparseCheckout?: SparseCheckoutUpdate; + dangerouslyForceDiscardAll?: boolean; +} +``` + +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 UpdateRepoRequest { + id?: bigint; + ref?: GitRef; + sparseCheckout?: SparseCheckoutUpdate; +} +``` + +This is a wire-compatible rename; the zod transform can flatten back to +`{branch, tag}` on the way out. + +### M3. `req.id ?? ''` URL-builder bug-shape + +```ts +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:115, 144, 234`. diff --git a/.agent/naming-audit/resourcequotas.md b/.agent/naming-audit/resourcequotas.md new file mode 100644 index 00000000..70cdf979 --- /dev/null +++ b/.agent/naming-audit/resourcequotas.md @@ -0,0 +1,51 @@ +# Naming Audit: `resourcequotas` package (v1) + +**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). + +--- + +## Summary + +| Severity | Count | +| --------- | ----- | +| High | 0 | +| Medium | 1 | +| Low | 1 | +| **Total** | **2** | + + +Headline themes: + +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 + +_None._ + +--- + +## Medium Severity + +### M1. `QuotaInfo` carries the redundant `Info` suffix + +- **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` discussion in `catalogs.md` §2.1 — repo-wide pattern. + +--- + +## Low Severity + +### L1. `req` parameter name on every client method + +- **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 `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, 118, 131, 134, 137` — same shorthand, lower priority. diff --git a/.agent/naming-audit/rfa.md b/.agent/naming-audit/rfa.md new file mode 100644 index 00000000..2763df3f --- /dev/null +++ b/.agent/naming-audit/rfa.md @@ -0,0 +1,58 @@ +# Naming Audit: rfa + +**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:** 7 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 6 | + +## High severity + +### 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. +- **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 + +### 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: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: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: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: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: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. diff --git a/.agent/naming-audit/schemas.md b/.agent/naming-audit/schemas.md new file mode 100644 index 00000000..8438999d --- /dev/null +++ b/.agent/naming-audit/schemas.md @@ -0,0 +1,95 @@ +# Naming Audit: `schemas` package (v1) + +**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). + +--- + +## Findings + +### 1. Overly verbose + +#### 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. + +--- + +### 2. Redundant suffixes + +#### 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`, +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. + +#### 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:60, 206, 158) +`options` collides with the SDK's own `CallOptions` parameter name +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`. + +--- + +### 4. Field contradicting type domain + +#### 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). +- `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. + +#### 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:179-200). + +--- + +### 5. Go / Java-style names + +#### 5.1 `…Info` suffix (`SchemaInfo`, `EffectivePredictiveOptimizationFlag`) +Java/Go style. TS convention is to drop it. See §2.1. + +--- + +### 6. Proto-architectural-leak naming + +#### 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 + 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 + §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. diff --git a/.agent/naming-audit/scim.md b/.agent/naming-audit/scim.md new file mode 100644 index 00000000..07ffb73b --- /dev/null +++ b/.agent/naming-audit/scim.md @@ -0,0 +1,43 @@ +# 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:** 4 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 2 | +| Low | 1 | + +## High severity + +### 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: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: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`. +- **Rationale:** `Op` is a proto shorthand for "operation"; the TS type name should spell it out, and the `_PatchOp` re-suffix should vanish. + +## Low severity + +### 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. diff --git a/.agent/naming-audit/secrets.md b/.agent/naming-audit/secrets.md new file mode 100644 index 00000000..d5195ffa --- /dev/null +++ b/.agent/naming-audit/secrets.md @@ -0,0 +1,101 @@ +# 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` + +--- + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 1 | +| Medium | 3 | +| **Total** | **4** | + +Headline themes: + +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. + +--- + +## High Severity + +### H1. Inconsistent action verb: `Put*` mixed with `Create*` and `Delete*` + +- **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: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 + (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. + +--- + +## Medium Severity + +### M1. `AclItem` is generic-suffix tautology + +- **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: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: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 + 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. + +### M3. `ScopeBackendType` enum name is an architectural leak + +- **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 + 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 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 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). diff --git a/.agent/naming-audit/secretsuc.md b/.agent/naming-audit/secretsuc.md new file mode 100644 index 00000000..08dec2f5 --- /dev/null +++ b/.agent/naming-audit/secretsuc.md @@ -0,0 +1,34 @@ +# Naming Audit: secretsuc + +**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:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| 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: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. + +## Medium severity + +### 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. + +### 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. diff --git a/.agent/naming-audit/settings.md b/.agent/naming-audit/settings.md new file mode 100644 index 00000000..57e86a66 --- /dev/null +++ b/.agent/naming-audit/settings.md @@ -0,0 +1,172 @@ +# 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 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:** 19 + +--- + +## Summary table + +| # | Severity | Category | Identifier | File:line | +|---|----------|----------|------------|-----------| +| 1 | Critical | Vague package name | `settings` (package) | package level | +| 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` | + +--- + +## 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 of the settings surface. + +--- + +## High severity + +### 2. `Setting` — extreme generic risk + +- **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: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: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: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. +- **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). + +### 5. `Aibi` — undefined cryptic abbreviation (AI/BI) + +- **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: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: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` + - `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. + +### 9. `AllowedAppsUserApiScopesMessage` — `Api` mid-position proto leak + +- **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. +- **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 + +### 10. `*Public*` qualifier — redundant + +- **File:line:** `model.ts:204, 318, 218, 334, 209, 325` +- **Category:** Redundant qualifier +- **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. + +### 11. Method names: `getPublic*`, `patchPublic*` — redundant `Public` + +- **File:line:** `client.ts:80, 355, 136, 420, 110, 388` +- **Category:** Redundant qualifier + verbose +- **Suggestion:** `getAccountSetting`, `patchAccountSetting`, etc. + +### 12. `patch*` — HTTP-verb leak where the SDK convention is `update`/`set` + +- **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. + +### 13. `patchPublicAccountUserPreference` (single user-pref item) — overly verbose action + +- **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. + +### 14–16. Long type names + +- **File:line:** `model.ts:277, 256, 325` +- **Category:** Overly verbose +- **Identifiers:** + - `ListAccountUserPreferencesMetadataResponse` (42 chars) + - `ListAccountUserPreferencesMetadataRequest` (41 chars) + - `PatchPublicAccountUserPreferenceRequest` (39 chars) +- **Suggestion:** After applying the suggested simplifications (drop `Public`), names shorten naturally: `ListUserPreferencesMetadataResponse`, etc. + +### 17. `*Public*` qualifier as proto-architectural leak (reframe of #10) + +- **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 #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 + +### 18. `IntegerMessage` misleading in JS + +- **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. + +### 19. `patch*` vs `update*`/`set*` + +- See #12. diff --git a/.agent/naming-audit/sharing.md b/.agent/naming-audit/sharing.md new file mode 100644 index 00000000..264697c6 --- /dev/null +++ b/.agent/naming-audit/sharing.md @@ -0,0 +1,99 @@ +# Naming Audit: sharing + +**Path:** `packages/sharing/src/v1/` +**Versions audited:** v1 +**Files audited:** `model.ts`, `client.ts`, `utils.ts`, `transport.ts`, `index.ts` +**Total weird names flagged:** 3 + +## Summary + +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 1 | +| Low | 1 | +| **Total** | **3** | + +--- + +## High severity (must fix) + +### 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: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` + 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`, + `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`, + 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. + +--- + +## Medium severity (worth pushing back on) + +### 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: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: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 + `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: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: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. +- **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. diff --git a/.agent/naming-audit/statementexecution.md b/.agent/naming-audit/statementexecution.md new file mode 100644 index 00000000..8845687f --- /dev/null +++ b/.agent/naming-audit/statementexecution.md @@ -0,0 +1,124 @@ +# 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`. + +**Total weird names flagged:** 17 + +## Summary + +| Severity | Count | +| --- | --- | +| High | 5 | +| Medium | 10 | +| Low | 2 | + +## High severity + +### 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: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: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: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: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. +- **Rationale:** Names should match the official API where possible. Compare to `getStatementResultChunkN` in the Go SDK. + +## Medium severity + +### 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: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: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: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: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. +- **Rationale:** Two-of-N fields where only one is populated should be modelled as a union. + +### 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:** Generator-wide pattern — the codegen emits every request field as optional across packages. + +### 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: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: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. `*_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". +- **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 + +### 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. + +### 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. diff --git a/.agent/naming-audit/storageconfigurations.md b/.agent/naming-audit/storageconfigurations.md new file mode 100644 index 00000000..980afae2 --- /dev/null +++ b/.agent/naming-audit/storageconfigurations.md @@ -0,0 +1,49 @@ +# 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 + +## Summary + +| Severity | Count | +| -------- | ----- | +| High | 4 | + +## High severity + +### 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 + 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: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. + +### 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. + +### 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. diff --git a/.agent/naming-audit/supervisoragents.md b/.agent/naming-audit/supervisoragents.md new file mode 100644 index 00000000..31d9ebf4 --- /dev/null +++ b/.agent/naming-audit/supervisoragents.md @@ -0,0 +1,33 @@ +# 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). 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:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | + +## High severity + +### 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 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. diff --git a/.agent/naming-audit/systemschemas.md b/.agent/naming-audit/systemschemas.md new file mode 100644 index 00000000..11cf31a4 --- /dev/null +++ b/.agent/naming-audit/systemschemas.md @@ -0,0 +1,37 @@ +# Naming Audit: systemschemas + +**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:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Medium | 1 | +| Low | 1 | + +## High severity + +### 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. + +## Medium severity + +### 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". + +## Low severity + +### 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. diff --git a/.agent/naming-audit/tables.md b/.agent/naming-audit/tables.md new file mode 100644 index 00000000..2ea09064 --- /dev/null +++ b/.agent/naming-audit/tables.md @@ -0,0 +1,123 @@ +# Naming Audit: `tables` (v1) + +**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/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`). + +**Go reference:** `databricks/sdk-go` `databricks/api/` (the 1:1 port source). + +--- + +## Summary (counts) + +| Severity | Count | +| --------------------- | ----- | +| **Total findings** | **6** | + +(Findings often span multiple audit categories; counts above are unique +findings.) + +--- + +## Findings + +### 1. `Kv` is a cryptic abbreviation in `DeltaRuntimePropertiesKvPairs` — category 5 (Cryptic abbreviations) and category 8 (Redundant suffixes) + +**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 +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). + +--- + +### 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 +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 258, 280 acknowledge the +non-idiomatic shape. + +--- + +### 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`, +`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. + +--- + +### 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. + +**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". + +--- + +### 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`). +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`. + +**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. + +--- + +### 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`. + +**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. diff --git a/.agent/naming-audit/tagassignments.md b/.agent/naming-audit/tagassignments.md new file mode 100644 index 00000000..0159bd6f --- /dev/null +++ b/.agent/naming-audit/tagassignments.md @@ -0,0 +1,27 @@ +# Naming Audit: tagassignments + +**Path:** `packages/tagassignments/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| 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: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. +- **Rationale:** The shape `req.entityType ?? ''` betrays the contract: nullable input cannot legally produce a valid URL. Generator-wide concern. + +## Medium severity + +### 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. diff --git a/.agent/naming-audit/tagpolicies.md b/.agent/naming-audit/tagpolicies.md new file mode 100644 index 00000000..4cdbd045 --- /dev/null +++ b/.agent/naming-audit/tagpolicies.md @@ -0,0 +1,25 @@ +# 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 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:** 2 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | + +## 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: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 `${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. diff --git a/.agent/naming-audit/tokenmanagement.md b/.agent/naming-audit/tokenmanagement.md new file mode 100644 index 00000000..e9e8f7ef --- /dev/null +++ b/.agent/naming-audit/tokenmanagement.md @@ -0,0 +1,43 @@ +# 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/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:** 4 + +## Summary +| Severity | Count | +| --- | --- | +| High | 2 | +| Medium | 1 | +| Low | 1 | + +## 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: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-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. + +## 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: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. + +## Low severity + +### 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. +- **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. diff --git a/.agent/naming-audit/tokens.md b/.agent/naming-audit/tokens.md new file mode 100644 index 00000000..c853fff2 --- /dev/null +++ b/.agent/naming-audit/tokens.md @@ -0,0 +1,33 @@ +# Naming Audit: tokens + +**Path:** `packages/tokens/src/v1/` +**Versions audited:** v1 +**Total weird names flagged:** 3 + +## Summary +| Severity | Count | +| --- | --- | +| High | 1 | +| Low | 1 | +| Observation | 1 | + +## High severity + +### 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. +- **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. + +## Low severity + +### 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`. +- **Rationale:** Exporting per-type mask builders is a Go-port artefact; native TS would lean on `Partial` + key inference. + +## Observations + +### 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 new file mode 100644 index 00000000..4ba65a61 --- /dev/null +++ b/.agent/naming-audit/usagedashboards.md @@ -0,0 +1,52 @@ +# 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:** 6 + +## Summary +| Severity | Count | +| --- | --- | +| High | 3 | +| Medium | 3 | + +## 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. `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: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, 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: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: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. diff --git a/.agent/naming-audit/vectorsearch.md b/.agent/naming-audit/vectorsearch.md new file mode 100644 index 00000000..93b197e4 --- /dev/null +++ b/.agent/naming-audit/vectorsearch.md @@ -0,0 +1,40 @@ +# Naming Audit: vectorsearch + +**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:** 3 + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 1 | +| Medium | 2 | +| **Total** | **3** | + +--- + +## High severity + +### 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:** `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: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. `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 new file mode 100644 index 00000000..093876f8 --- /dev/null +++ b/.agent/naming-audit/volumes.md @@ -0,0 +1,89 @@ +# Naming Audit: `volumes` (v1) + +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`. + +## Summary + +| Severity | Count | +| --------- | ----- | +| High | 1 | +| Medium | 3 | +| **Total** | **4** | + +--- + +## High Severity + +### H1. `Create*` / `Update*` request types include server-only fields + +- **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 + 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 `CreateVolumeRequest`: + `name`, `catalogName`, `schemaName`, `volumeType`, `storageLocation`, + `comment`. For `UpdateVolumeRequest`: `fullNameArg` (the path + identifier), `newName`, `owner`, `comment` (per the method docstring at + `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: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. + +--- + +## Medium Severity + +### M1. `VolumeInfo` — redundant `Info` suffix + +- **File / line:** `src/v1/model.ts:173`. +- **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. + +### M2. `browseOnly` is a server-derived flag on request types + +- **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 + 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 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 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: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 + 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. diff --git a/.agent/naming-audit/warehouses.md b/.agent/naming-audit/warehouses.md new file mode 100644 index 00000000..f1b265e7 --- /dev/null +++ b/.agent/naming-audit/warehouses.md @@ -0,0 +1,352 @@ +# 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/index.ts` +- `src/v1/utils.ts` +- `src/v1/transport.ts` + +## Summary + +| Severity | Count | +| ----------- | ----- | +| High | 13 | +| Medium | 6 | +| Low | 6 | +| **Total** | **25** | + +--- + +## F0 — Package-level: legacy "Endpoint" terminology leaks through the warehouse package + +### 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 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`, + `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). Reconcile with the package brand. + +--- + +## Findings + +### 1. Vague / generic names + +#### F1.1 — `EndpointInfo` type name (HIGH) +- **Where:** `model.ts:1045`, `index.ts:35`, return field + `warehouses?: EndpointInfo[]` on `ListWarehousesResponse` + (`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 + `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 + `GetWarehouseResponse` shape into a single canonical type. + +#### F1.2 — `EndpointState` enum name (HIGH) +- **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:708`) 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: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:713`) — a warehouse + health message. +- **Suggestion:** Rename to `WarehouseHealth` / + `WarehouseHealth_Status`. + +#### F1.4 — `EndpointTags`, `EndpointTagPair` interface names (HIGH) +- **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:851, 998, 1117, 1252`). +- **Suggestion:** Rename to `WarehouseTags` / `WarehouseTagPair`. + +#### F1.5 — `EndpointConfPair`, `RepeatedEndpointConfPairs` (HIGH) +- **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 + conflates the legacy "endpoint" term with workspace config. +- **Suggestion:** Rename `EndpointConfPair` → `ConfigPair` or + `WarehouseConfigPair`. `RepeatedEndpointConfPairs` → + `RepeatedConfigPairs`. + +#### F1.6 — `EndpointSecurityPolicy`, `EndpointSpotInstancePolicy` (HIGH) +- **Where:** `model.ts:36, 64`, `index.ts:14, 15`. Field on + `SetWorkspaceWarehouseConfigRequest.securityPolicy` + (`model.ts:1398`), + `GetWorkspaceWarehouseConfigResponse.securityPolicy` + (`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 + uses "endpoint" — see F0 above. +- **Suggestion:** Rename to `WarehouseSecurityPolicy` / + `WarehouseSpotInstancePolicy`. + +#### F1.7 — `Channel` type and `ChannelName` enum (MEDIUM) +- **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`, + `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 the type to `WarehouseChannel` and the + enum to `WarehouseChannelName` (or `DbsqlChannel` / + `DbsqlChannelName`). Note: the enum name `ChannelName` + duplicates "name" — see F4.2. + +#### F1.8 — `req` parameter name on every client method (LOW, Go-ism) +- **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:163`). +- **Why flagged:** Same Go abbreviation as `req`. See F5.1. +- **Suggestion:** `response` for consistency. Generator-level. + +--- + +### 2. Cryptic abbreviations + +#### F2.1 — `Conf` for configuration (`EndpointConfPair`) (MEDIUM) +- **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`. + +--- + +### 3. Misleading names + +#### F3.1 — `EndpointInfo` for a warehouse record (HIGH) +- **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 — `EndpointConfPair` / `RepeatedEndpointConfPairs` are workspace config, not endpoint config (HIGH) +- **Where:** `model.ts:1027, 1385`. Used inside + `GetWorkspaceWarehouseConfigResponse.dataAccessConfig` + (`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.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.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 + create). Surfacing it as settable on `Edit` is misleading. +- **Suggestion:** Spec-level. Mark read-only on response types + only. + +#### 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: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: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 + `terminal()` (any terminal state). Cross-cutting waiter API + decision. + +--- + +### 4. Redundant suffixes + +#### F4.1 — `Request` suffix on every request interface (HIGH, generator-driven) +- **Where:** `CreateDefaultWarehouseOverrideRequest`, + `CreateWarehouseRequest`, + `DeleteDefaultWarehouseOverrideRequest`, + `EditWarehouseRequest`, `GetDefaultWarehouseOverrideRequest`, + `GetWarehouseRequest`, `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. 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. + +#### 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 + "Channel Type". +- **Suggestion:** Rename the enum to `ChannelType` (this also + clarifies intent — Custom vs. Preview is the *type* of channel). + +#### 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 + shape already evident from the fields. +- **Suggestion:** Rename `EndpointTagPair` → `Tag`, + `EndpointConfPair` → `Config`, `WarehouseTypePair` → + `WarehouseTypeAvailability` (or similar) — semantically clearer + than the `Pair` suffix. + +--- + +### 5. Go/Java-style names + +#### 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 + uses `options` (full word) so the abbreviation is inconsistent + within the same method signature. +- **Suggestion:** Generator-level. + +#### 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. + +--- + +### 6. Inconsistent action verbs + +#### 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 + "update"; the warehouse `edit` is a legacy form. Compounded + by `Editor`-ish naming on types: `EditWarehouseRequest`, + `EditWarehouseResponse`, `EditWarehouseWaiter`. +- **Suggestion:** Standardize on `update` across the SDK. + Rename `editWarehouse` → `updateWarehouse`, + `EditWarehouseRequest` → `UpdateWarehouseRequest`, + `EditWarehouseWaiter` → `UpdateWarehouseWaiter`. Note: this is + a method/operation rename — coordinate with backend. + +--- + +### 7. Type-suffix tautology + +#### F7.1 — `Channel.name: ChannelName` (HIGH) +- **Where:** `model.ts:763-766`. + ```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 the enum to `ChannelType`, which breaks + 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; + 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 the enum type `WarehouseType` → `Type` + (or rename the container to `WarehouseTypeAvailability`) to + break the duplication. diff --git a/.agent/naming-audit/workspacebindings.md b/.agent/naming-audit/workspacebindings.md new file mode 100644 index 00000000..c08081ba --- /dev/null +++ b/.agent/naming-audit/workspacebindings.md @@ -0,0 +1,23 @@ +# Naming Audit: workspacebindings + +**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:** 1 + +## Summary +| Severity | Count | +| --- | --- | +| Medium | 1 | + +A redundant Go-style `Info` suffix makes up the single finding. + +--- + +## Medium severity + +### 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. diff --git a/.agent/naming-audit/workspaces.md b/.agent/naming-audit/workspaces.md new file mode 100644 index 00000000..4dc71456 --- /dev/null +++ b/.agent/naming-audit/workspaces.md @@ -0,0 +1,48 @@ +# 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:** 3 + +## Summary + +| Severity | Count | +| ------------ | ----- | +| High | 3 | + +## High severity + +### 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. +- **Category:** Proto-architectural leak — `Public` suffix on client + method. +- **Suggested:** `createWorkspace`. +- **Rationale:** Methods on `WorkspacesClient` are inherently public; the suffix + is meaningless to a TS caller. + +### 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`. +- **Rationale:** Same as #1. + +### 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 + 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. diff --git a/AGENTS.md b/AGENTS.md index 10b54bce..7b6aeff0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -114,3 +114,185 @@ 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`. + +## 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 + +_None._ + +(When populated, each line is one TODO in the form: +`- YYYY-MM-DD — `.) + +## 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. + +**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 +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 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 +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 + +**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 ~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`. +- 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.