Skip to content

Commit 83b95fb

Browse files
claude[bot]github-actions[bot]claudeninja-shreyash
authored
docs: update Claude docs from PR review analysis (#360)
* docs: update claude docs from PR review analysis (2026-04-01 to 2026-04-08) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: update claude docs from PR review analysis (2026-04-06 to 2026-04-13) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: strip source PR refs and reviewer mentions from doc bodies Doc files should be self-contained guidance, not a changelog. Removes (Source: PR #N) and @Reviewer references from the new rules/conventions introduced in this PR. Provenance stays in the PR description. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: remove internal naming rule from rules.md Co-authored-by: Shreyash <ninja-shreyash@users.noreply.github.com> * docs: consolidate rules.md anti-patterns into conventions.md Move all coding anti-patterns (NEVER rules) from rules.md into conventions.md as inline annotations next to their related conventions. rules.md now only contains testing, documentation, and quality guidelines. - Add inline NEVERs to conventions.md only where they add non-obvious value (specific traps, unique why) — not mere inversions - Remove entire NEVER Do section from rules.md, rename to Testing & Quality - Fold unique test/docs NEVERs into their respective sections in rules.md - Update enhance-claude-docs skill to route anti-patterns to conventions.md - Move output/attachment indicator to Service model section per review feedback - Incorporate PR #360 new insights in correct locations Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: shreyash0502 <shreyash9129@gmail.com> Co-authored-by: Shreyash <ninja-shreyash@users.noreply.github.com>
1 parent 52d0a4b commit 83b95fb

3 files changed

Lines changed: 48 additions & 90 deletions

File tree

.claude/skills/enhance-claude-docs/SKILL.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ For each thread that passes Stage 1, determine if it contains a documentation-wo
136136

137137
| Signal | Target file |
138138
|--------|-------------|
139-
| Reviewer correcting a pattern violation not yet in rules | `agent_docs/rules.md` |
139+
| Reviewer correcting a pattern violation or convention (including anti-patterns) | `agent_docs/conventions.md` (add inline **NEVER** next to the relevant convention) |
140140
| Explaining WHY a convention exists or should be followed | `agent_docs/conventions.md` |
141+
| New testing guidelines or quality rules | `agent_docs/rules.md` (testing & quality only) |
141142
| New project structure info, service patterns, or architecture decisions | `agent_docs/architecture.md` |
142143
| New commands, quick-reference items, or workflow changes | `Agents.md` |
143144
| Top-level pointers or high-level project changes (rare) | `CLAUDE.md` |
@@ -170,8 +171,8 @@ If actionable insights exist:
170171

171172
1. For each insight, determine the correct file and section.
172173
2. Edit the files using the Edit tool. Follow existing formatting, heading levels, and conventions in each file.
173-
3. For `agent_docs/rules.md`, add new items under the appropriate "NEVER" subsection or create a new subsection if needed. Follow the existing pattern: bold "NEVER" + action, followed by explanation with rationale.
174-
4. For `agent_docs/conventions.md`, add to the relevant section or create a new subsection following existing patterns.
174+
3. For `agent_docs/conventions.md`, add conventions and anti-patterns to the relevant section. Anti-patterns go inline as **NEVER** next to the related convention — only when they add a non-obvious *why* or call out a specific trap. Do not add NEVERs that merely restate the convention in negative form.
175+
4. For `agent_docs/rules.md`, add only testing guidelines, integration test rules, documentation/JSDoc rules, or quality checklist items. This file does not contain coding conventions or anti-patterns — those belong in `conventions.md`.
175176
5. For `agent_docs/architecture.md`, update tables or sections as appropriate.
176177
6. For `Agents.md`, update the quick reference or add new sections.
177178

agent_docs/conventions.md

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,21 @@
77
- **UPPER_SNAKE_CASE**: constants (`DEFAULT_PAGE_SIZE`, `TASK_ENDPOINTS`)
88
- **File names**: kebab-case for general files (`api-client.ts`), dot-separated for type/model files (`tasks.types.ts`, `tasks.models.ts`)
99
- Prefer `private` keyword over underscore prefix for private methods
10-
- No `any` type — use `unknown` if truly unknown, then validate
11-
- Mark optional fields as optional in type interfaces
10+
- No `any` type — use `unknown` if truly unknown, then validate.
11+
- **NEVER** use `as unknown as` type casts — refactor to make types flow naturally. Casts hide real type errors and break when upstream types change.
12+
- Mark optional fields as optional in type interfaces — over-requiring causes runtime `undefined` access on fields the API didn't return.
13+
- Use enums for fixed value sets — **NEVER** leave raw strings/numbers. Raw values lose type safety and autocomplete.
14+
- **NEVER** write `param || {}` for required parameters — this hides bugs by silently accepting missing required data at call sites.
1215

1316
## General conventions
1417

1518
- Services follow the pattern: extend `BaseService`, call `super(uiPath)`, use `this.get()` / `this.post()` etc.
1619
- Types live in `src/models/{domain}/{domain}.types.ts`. Internal-only types go in `*.internal-types.ts`.
1720
- Constants live in `src/utils/constants/`. Endpoints are split per domain in `src/utils/constants/endpoints/` (e.g., `data-fabric.ts`, `maestro.ts`, `orchestrator.ts`).
1821
- Subpath exports: when adding a new service module, add entries to `package.json` `exports` and `rollup.config.js`.
19-
- Every public service method must be decorated with `@track('ServiceName.MethodName')` for telemetry.
22+
- Every public service method must be decorated with `@track('ServiceName.MethodName')` for telemetry — gaps are invisible until production debugging, when they're expensive.
2023
- Use named imports/exports (avoid default exports). Use barrel exports (`index.ts`) for public API. Never export internal types from barrel exports.
24+
- **Barrel files must use `export * from`**, not `export type * from`. Using `export type` re-exports only type declarations and silently drops runtime values (class constructors, enums), causing `undefined` errors for SDK consumers who import them.
2125

2226
## Type naming
2327

@@ -26,10 +30,12 @@
2630
- **Final response type**: `type {Entity}GetResponse = Raw{Entity}GetResponse & {Entity}Methods` — defined in `*.models.ts`, combining raw data with bound methods.
2731
- **Options types**: `{Entity}GetAllOptions`, `{Entity}GetByIdOptions`, `{Entity}{Operation}Options` (e.g., `TaskAssignmentOptions`, `ProcessInstanceOperationOptions`). Compose with `RequestOptions & PaginationOptions & { ... }` for list methods.
2832
- **Common base types**: `BaseOptions` (expand, select), `RequestOptions` (extends BaseOptions with filter, orderby), `OperationResponse<TData>` (success + data) — all from `src/models/common/types.ts`.
29-
- **Use "Options" not "Request"** for parameter types — never `{Entity}{Operation}Request`.
33+
- **Use "Options" not "Request"** for parameter types — the entire SDK uses `{Entity}{Operation}Options`.
3034
- **Required parameters are always positional; Options objects are reserved for optional parameters only.** Required values (IDs, keys, data) are positional arguments. Options objects are always the last parameter, always marked `?`, and contain only optional fields. E.g., `getOutput(jobKey: string)` not `getOutput(options: { jobKey: string })`, `close(instanceId, folderKey, options?)` not `close(options: { instanceId, folderKey })`.
35+
- **NEVER** duplicate fields across option types — extend existing ones. If `CaseInstanceOperationOptions` already has `comment`, extend it instead of re-declaring. When the shape is identical, use `extends` (e.g., `export interface EntityUpdateRecordByIdOptions extends EntityGetRecordByIdOptions {}`).
36+
- **NEVER** use type aliases for response types — even when the shape matches an existing one, use an `extends` interface. Type aliases (e.g., `export type EntityUpdateRecordResponse = EntityRecord`) break TypeDoc docs generation by not rendering as standalone types. Use `export interface EntityUpdateRecordResponse extends EntityRecord {}` instead.
3137

32-
Method names: **singular** for single-item ops (`insertRecordById`), **plural** for batch (`insertRecordsById`). Prefer plurals over `batch` prefix.
38+
Method names: **singular** for single-item ops (`insertRecordById`), **plural** for batch (`insertRecordsById`). **NEVER** use `batch` prefix — the SDK convention is singular/plural to distinguish cardinality.
3339

3440
**Singular vs batch patterns:**
3541

@@ -52,15 +58,17 @@ The method attachment pattern:
5258
- `create{Entity}WithMethods(rawData, service)` — merges raw data + methods via `Object.assign({}, rawData, methods)`
5359
- Methods validate required fields (`if (!data.id) throw new Error(...)`) before delegating
5460

61+
**Include output/attachment indicator fields in response types:** When an entity response can reference a file or attachment (e.g., `outputFile` on a Job indicating a blob attachment key), include that field in `Raw{Entity}GetResponse` even if the primary retrieval method does not fetch the file. This lets callers check for output availability without an extra API call.
62+
5563
## Method attachment (when to bind methods to response objects)
5664

5765
- **Not every service method gets bound.** Only bind methods that operate ON a specific entity after retrieval — state-changing operations (assign, cancel, complete, insert, update, delete) and contextual reads that need the entity's ID.
58-
- **Never bind**: `getAll()`, `getById()`, `create()`, and cross-entity queries like `getUsers()`.
66+
- **NEVER** bind `getAll()`, `getById()`, `create()`, or cross-entity queries — these are service-level entry points. Binding them creates circular nonsense (an entity that retrieves itself).
5967
- **Read-only services don't bind at all** — Assets, Buckets, Queues, Processes, ChoiceSets, Cases, and ProcessIncidents have no `{Entity}Methods` interface.
6068

6169
## Response transformation pipeline
6270

63-
Transform functions live in `src/utils/transform.ts`. Not every service uses every step — inspect the actual API response to decide which are needed.
71+
Transform functions live in `src/utils/transform.ts`. Not every service uses every step — inspect the actual API response to decide which are needed. Each step must be justified by what the API actually sends. Never return raw API responses — apply all applicable pipeline steps.
6472

6573
**Available steps (apply in this order, skip any that don't apply):**
6674

@@ -81,7 +89,9 @@ Transform functions live in `src/utils/transform.ts`. Not every service uses eve
8189

8290
**Outbound requests** (SDK → API): use `transformRequest(data, {Entity}Map)` (auto-reverses field map) and `camelToPascalCaseKeys()`.
8391

84-
**Field maps vs case conversion:** `{Entity}Map` is for semantic renames only. Case conversion is handled by `pascalToCamelCaseKeys()`. Do not add case-only entries to a field map.
92+
**Field maps vs case conversion:** `{Entity}Map` is for semantic renames only. Case conversion is handled by `pascalToCamelCaseKeys()`. **NEVER** add case-only entries to a field map — mixing them causes double-conversion bugs.
93+
94+
**Data Fabric exception:** Do NOT apply `pascalToCamelCaseKeys()` or any field-rename transforms to Data Fabric entity record data (`EntityRecord`, record fields returned by `getRecordById`, `getAllRecords`, etc.). DF entity field names are user-defined schema columns and must be returned exactly as the API sends them — casing is part of the schema contract. Only system-generated DF fields (e.g., `Id`, `CreatedBy`) use PascalCase, and those are also left untransformed to keep behavior consistent.
8595

8696
## Endpoint constants
8797

@@ -91,8 +101,9 @@ Defined in `src/utils/constants/endpoints/` with separate files per domain (e.g.
91101
- Parameterized endpoints: arrow functions — `GET_BY_ID: (id: string) => '${BASE}/api/v1/instances/${id}'`
92102
- Operation endpoints: `CANCEL: (id: string) => '${BASE}/api/v1/instances/${id}/cancel'`
93103
- All objects use `as const`
94-
- **Group nested endpoints logically** (e.g., `ENTITY.ATTACHMENT.DOWNLOAD` not flat).
95-
- **Use consistent param names** across endpoints. Avoid redundancy.
104+
- **Group nested endpoints logically** (e.g., `ENTITY.ATTACHMENT.DOWNLOAD` not flat). Use short names — under a `CASE` group, use `REOPEN` not `REOPEN_CASE` since the group context already provides the prefix.
105+
- **Use consistent param names** across endpoints in the same group — if one endpoint uses `instanceId`, all should.
106+
- **NEVER** copy-paste JSDoc comments between endpoint groups — each constant needs its own comment. A "Asset Service Endpoints" comment on `JOB_ENDPOINTS` is a review rejection.
96107

97108
## Pagination
98109

@@ -124,6 +135,7 @@ Naming: `{SERVICE}_PAGINATION` for response shape, `{SERVICE}_OFFSET_PARAMS` or
124135

125136
## Export naming
126137

138+
- **NEVER** use internal product/team names in service file paths or class names — use the user-facing domain name instead. E.g., name the file `feedback.ts` under `conversational-agent/feedback/`, not `llmops.ts` under `llmops/`. Internal product names change and leak internal team organization into the public API.
127139
- Internal class: `{Entity}Service` (e.g., `EntityService`, `TaskService`)
128140
- Public alias in `index.ts`: plural noun (e.g., `EntityService as Entities`, `TaskService as Tasks`)
129141
- Legacy services export both names for backward compatibility
@@ -137,6 +149,8 @@ Types in `{domain}.types.ts` are public (re-exported through barrel). Types in `
137149

138150
**Put in `types.ts`:** All types in public method signatures, `Raw{Entity}GetResponse` types that users compose with `{Entity}Methods`.
139151

152+
**NEVER** re-export `internal-types.ts` through `index.ts` — re-exporting pollutes the public API and creates breaking-change risk when internal formats change.
153+
140154
## OData prefix pattern
141155

142156
OData APIs require `$` prefix on query params. The SDK accepts clean camelCase keys and adds the prefix via `addPrefixToKeys()` from `src/utils/transform.ts`.
@@ -168,13 +182,14 @@ constructor(instance: IUiPath) {
168182
}
169183
```
170184

171-
If the constructor only calls `super()` with no additional setup, omit it entirely (redundant constructor rule).
185+
If the constructor only calls `super()` with no additional setup, omit it entirely.
172186

173187
## Error types
174188

175-
- **`ValidationError`** — for **user input validation only**: missing required params, invalid option values, malformed user-provided data. Example: `if (!jobKey) throw new ValidationError(...)`.
189+
- **`ValidationError`** — for **user input validation only**: missing required params, invalid option values, malformed user-provided data. Example: `if (!jobKey) throw new ValidationError(...)`. **NEVER** use for server-side issues like failed JSON parsing — use `ServerError` instead. Misusing it misrepresents the error source.
176190
- **`ServerError`** — for server-side issues: failed JSON parsing of API responses, unexpected response formats, API returning unparseable data. Example: `catch { throw new ServerError({ message: 'Failed to parse output as JSON' }) }`.
177191
- **`ErrorFactory.createFromHttpStatus()`** — for HTTP error responses from external calls (blob downloads, etc.). Maps status codes to typed errors automatically.
192+
- **NEVER** add unnecessary type casts on already-typed values — if `blobAccess.headers` is already `Record<string, string>`, use a simple spread `{ ...blobAccess.headers }` instead of `arrayDictionaryToRecord()` with `as unknown as` casts.
178193

179194
## BaseService
180195

@@ -212,3 +227,9 @@ interface OperationResponse<TData> { success: boolean; data: TData; }
212227
**Use for:** Lifecycle operations (cancel, pause, resume), bulk operations with error checking via `processODataArrayResponse()`.
213228

214229
**DO NOT use for:** `getAll()`, `getById()`, `create()`, methods returning entity data directly.
230+
231+
## Code hygiene
232+
233+
- **NEVER** leave unused code — unused imports, variables, redundant constructors that only call `super()`. Linter (oxlint) catches these.
234+
- **NEVER** commit sensitive files — `.env`, `credentials.json`, `*.key`, `*.pem`, hardcoded API keys/tokens.
235+
- **NEVER** define static lookup tables inside method bodies — move them to module-level constants or `*.internal-types.ts`. A static mapping that doesn't change between calls (e.g., `TaskTypeEndpoints`) rebuilt on every invocation wastes memory and hides structure.

0 commit comments

Comments
 (0)