# Pull Request Conventions

This document defines standards for pull requests in the Pinecone Python SDK.

## PRs Are Documentation

**Critical:** Pull requests are not just for code review—they are **permanent documentation** linked from release notes. Write PRs for SDK users, not just for internal reviewers. 

When users read release notes and click a PR link, they should find:
- Clear explanation of what changed and why it matters
- Realistic code examples they can adapt to their projects
- Migration guidance if breaking changes exist

Think of each PR as a mini-blog post about the feature or fix.

## Squash and Merge Workflow

**Important:** This repository uses GitHub's squash and merge workflow. When a PR is merged:
- **PR title becomes the commit subject line** - must follow Conventional Commits format
- **PR description becomes the commit message body** - can use rich markdown formatting
- Individual commit messages during development are less critical (they get squashed away)
- **Breaking changes must use `!` in title** (e.g., `feat!: require spec parameter`) AND include `BREAKING CHANGE:` in description for automated tooling

## Pull Request Title

### Format: Conventional Commits

Use Conventional Commits format for all PR titles. **CI automatically validates** PR titles and will fail if the format is incorrect.

```
<type>: <description>
```

### Types

| Type | Usage | Example |
|------|-------|---------|
| `feat` | New features or capabilities | `feat: add batch upsert support` |
| `fix` | Bug fixes | `fix: handle connection timeout errors` |
| `docs` | Documentation only | `docs: update migration guide` |
| `refactor` | Code changes without behavior change | `refactor: simplify error handling` |
| `perf` | Performance improvements | `perf: add connection pooling` |
| `test` | Test additions or changes | `test: add integration tests for collections` |
| `chore` | Build, tooling, dependencies | `chore: update httpx to 0.25.0` |
| `ci` | CI/CD changes | `ci: add benchmark workflow` |

### Title Guidelines

**Do:**
- Keep under 72 characters
- Use imperative mood: "add feature" not "adds feature" or "added feature"
- Be specific: "fix timeout in query operations" not "fix bug"
- Use lowercase after the colon
- **Add `!` after type for breaking changes**: `feat!: require spec parameter`

**Don't:**
- Include issue numbers in title (put in description)
- Use vague descriptions: "update code", "fix issues", "improvements"
- Use past tense or present continuous
- Forget the `!` for breaking changes (makes them invisible to tooling and users)

### Examples

```
✅ Good:
- feat: add serverless index configuration
- fix: validate vector dimensions before upsert
- docs: add batch operations guide
- perf: implement connection pooling for HTTP client
- feat!: require spec parameter in create_index (breaking change)
- fix!: change error response format (breaking change)

❌ Bad:
- Fixed #123 (no type, references issue)
- Add new feature (missing type)
- feat: Adds Support For Collections (wrong case, verbose)
- Update files (vague)
- feat: require spec parameter (breaking change missing !)
```

## Pull Request Description

### Structure

The PR description can use rich markdown formatting to clearly communicate the change. Use this recommended structure:

```markdown
## Problem

Clear statement of what problem this PR solves or what feature it adds.
Explain the current state and why change is needed.

## Solution

High-level description of the approach taken. Focus on "how" and "why"
this approach was chosen over alternatives.

## Key Decisions

Bullet points of significant technical decisions:
- Why this architecture pattern?
- Why this library/tool?
- Why this API design?

## Breaking Changes

**If introducing breaking changes, include this section with BREAKING CHANGE: prefix:**

BREAKING CHANGE: Description of what breaks and why.

- Explain impact on existing code
- Provide migration guidance
- Show before/after examples

## Examples

```python
# Realistic code example showing how to use the feature
from pinecone import Pinecone

pc = Pinecone(api_key="...")
# Clear example with comments
```

Explain examples in prose that SDK users can understand.

## Related

- Fixes #123
- Refs ABC-456
```

**Key Points:**
- Use markdown headers, code blocks, lists freely
- Explain "why" the change was made, not just "what" changed
- Include `BREAKING CHANGE:` prefix if breaking changes exist (enables automated tooling)
- End with issue references using magic words (`Fixes #123`)
- Include code examples when helpful
- Focus on architecture and user impact, avoid file lists

### Problem Section

**Purpose:** Establish context and motivation.

**Guidelines:**
- State the current situation clearly
- Explain why this change matters
- Focus on user/developer pain points
- Reference issues or discussions if applicable

**Good:**
```markdown
## Problem

The SDK creates a new HTTP connection for every request, leading to
poor performance when making multiple sequential queries. Users report
average latency of 150ms per query, with 50ms of that spent on
connection establishment.
```

**Bad:**
```markdown
## Problem

Added connection pooling.
```
(Doesn't explain the problem being solved)

### Solution Section

**Purpose:** Describe the approach and rationale.

**Guidelines:**
- Explain the high-level solution
- Describe key architectural decisions
- Explain why this approach over alternatives
- Mention any trade-offs made
- Keep implementation details minimal

**Good:**
```markdown
## Solution

This PR adds HTTP connection pooling using httpx's built-in pooling
capabilities. The HTTPClient maintains a pool of persistent connections,
reusing them across requests.

Chose httpx over alternatives because it provides both sync and async
clients with the same API, and HTTP/2 support will be straightforward
to add later.

Trade-off: Slightly higher memory usage (~2MB) for the connection pool,
but context manager support ensures proper cleanup.
```

**Bad:**
```markdown
## Solution

Modified HTTPClient class. Added pool_connections and pool_maxsize
parameters. Updated __init__ method.
```
(Too focused on "what" changed rather than "why")

### Key Decisions Section

**Purpose:** Document significant technical choices.

**Guidelines:**
- List important decisions made during implementation
- Explain the reasoning behind each
- Note alternatives considered
- Keep it concise (bullet points work well)

**Good:**
```markdown
## Key Decisions

- **httpx over requests**: Provides both sync and async clients with the
  same API, simplifying maintenance
- **Default pool sizes**: 10 keep-alive, 100 max - balances performance
  with memory usage based on typical SDK usage patterns
- **Context manager support**: Ensures proper cleanup without requiring
  explicit close() calls
```

**Bad:**
```markdown
## Key Decisions

- Used httpx
- Set pool_connections to 10
- Set pool_maxsize to 100
```
(Doesn't explain the reasoning)

### Breaking Changes Section

**Purpose:** Highlight changes that break existing code.

**Important for Squash and Merge:** When using GitHub's squash and merge, the PR description becomes the final commit message. Include `BREAKING CHANGE:` in the description to follow Conventional Commits and enable automated tooling (changelog generation, semantic versioning).

**Guidelines:**
- Only include if PR has breaking changes
- Start section with `BREAKING CHANGE:` prefix for Conventional Commits compliance
- List each breaking change clearly
- Explain impact on users
- Provide migration guidance
- Remove section if no breaking changes

**Examples:**

```markdown
## Breaking Changes

BREAKING CHANGE: The `create_index` method now requires a `spec` parameter.

### `create_index` now requires `spec` parameter

The `spec` parameter is now required to support serverless and pod-based
deployments.

**Old code:**
```python
pc.create_index(name="my-index", dimension=128)
```

**New code:**
```python
pc.create_index(
    name="my-index",
    dimension=128,
    spec={"serverless": {"cloud": "aws", "region": "us-east-1"}}
)
```

**Impact:** Existing code without `spec` will raise ValidationError.

**Migration:** Update all `create_index` calls to include spec parameter.
See [Migration Guide](docs/migration-guides/v1-to-v2.md) for details.

### Removed `legacy_upsert` method

The deprecated `legacy_upsert` method has been removed.

**Impact:** Code using `legacy_upsert` will raise AttributeError.

**Migration:** Replace `legacy_upsert` calls with `upsert`. The API is
identical except for the method name.
```

### Examples Section

**Purpose:** Provide realistic, copy-pasteable code that users can adapt. This is critical since PRs are linked from release notes.

**Guidelines:**
- **Write for end users**, not just internal developers
- Include complete, runnable code examples
- Use realistic variable names and scenarios that users relate to
- Show all necessary imports and setup
- Add comments explaining key points and non-obvious behavior
- Provide prose explanations that are understandable to SDK users
- Show common use cases first, then advanced patterns
- Make examples copy-pasteable and immediately useful

**Examples:**

```markdown
## Examples

### Basic Usage

```python
from pinecone import Pinecone

# Initialize client with connection pooling (default)
pc = Pinecone(api_key="your-api-key")

# Create index and query multiple times
index = pc.Index("example-index")

# Connection pooling makes sequential queries faster
for i in range(100):
    results = index.query(vector=[0.1] * 128, top_k=10)
    print(f"Query {i}: {len(results.matches)} results")
```

Connection pooling maintains up to 10 keep-alive connections, reducing
latency by ~30% for sequential operations. No code changes required -
pooling is enabled by default.

### Custom Pool Configuration

```python
from pinecone import Pinecone
from pinecone.config import HTTPConfig

# Configure custom pool settings for high-throughput applications
config = HTTPConfig(
    pool_connections=20,  # More keep-alive connections
    pool_maxsize=200,     # Support higher concurrency
)

pc = Pinecone(api_key="your-api-key", http_config=config)
```

Custom configuration is useful for applications with high query volume
or many concurrent operations.

### Context Manager (Recommended)

```python
from pinecone import Pinecone

# Use context manager to ensure proper cleanup
with Pinecone(api_key="your-api-key") as pc:
    index = pc.Index("example-index")
    results = index.query(vector=[0.1] * 128, top_k=10)
    # Connections automatically closed on exit
```

Using a context manager ensures connections are properly closed when done.
```

### Follow-up Items Section

**Purpose:** Track outstanding work and future improvements.

**Guidelines:**
- List tasks that should be done but aren't in this PR
- Note known limitations or edge cases
- Mention future enhancements to consider
- Use checkboxes for actionable items
- Don't list items that are already done

**Examples:**

```markdown
## Follow-up Items

- [ ] Add connection pool metrics to observability dashboard
- [ ] Document pool configuration in performance guide
- [ ] Consider adding automatic pool size tuning based on load
- Known limitation: Pool settings cannot be changed after client creation
- Future: Add support for per-index pool configuration
```

### Related Section

**Purpose:** Link to issues, PRs, and documentation.

**Guidelines:**
- Link related GitHub issues (use magic words)
- Link Linear issues if applicable
- Link related PRs
- Link relevant documentation
- Use proper magic words for automatic linking

**Magic Words:**
- `Fixes #123` - Closes GitHub issue
- `Refs #456` - References GitHub issue
- `Fixes ABC-789` - Closes Linear issue
- `Refs ABC-123` - References Linear issue

**Examples:**

```markdown
## Related

- Fixes #145 (connection pooling feature request)
- Refs #132 (related performance issue)
- Fixes SDK-234 (Linear: add connection pooling)
- See also: #140 (HTTP client refactor)
- Documentation: [Performance Guide](docs/conventions/performance.md)
- API Discussion: [RFC: Connection Pooling](https://github.com/pinecone-io/rfcs/pull/42)
```

## What to Avoid

### Don't Include

❌ **Long lists of files changed:**
```markdown
## Files Changed
- pinecone/__init__.py
- pinecone/_internal/client.py
... (50 more files)
```

Reviewers can see file changes in the PR. Focus on "why", not "what files".

❌ **Internal implementation details:**
```markdown
## Changes
- Refactored HTTPClient to use composition pattern
- Moved connection logic to ConnectionPool class
- Updated __init__ signatures
```

Users don't care about internal refactoring. Explain what they can do now that they couldn't before.

❌ **Implementation details:**
```markdown
## Changes
- Added try/except block on line 42
- Renamed variable `x` to `connection_pool`
- Fixed typo in comment
- Moved import to top of file
```

These details are visible in the code diff. Focus on architecture and decisions.

❌ **Vague descriptions:**
```markdown
## Summary
Updated some files to make things better. Fixed issues and improved performance.
```

Be specific about what changed and why.

❌ **Commit history:**
```markdown
## Commits
- WIP
- fix tests
- fix tests again
- address review comments
- final fix
```

Reviewers can see commit history. Summarize the overall change instead.

### Keep It Concise

**Good PR descriptions:**
- Focus on architecture and decisions
- Explain the "why" clearly
- Provide concrete examples
- Link to related issues
- Usually 200-400 words (excluding code)

**Bad PR descriptions:**
- List every file changed
- Focus on internal implementation details
- Repeat commit messages
- No code examples or user-focused explanation
- Written only for internal reviewers, not SDK users
- Often >1000 words or <50 words

## PR Metadata

### Labels

Apply a GitHub label to categorize the PR. Labels help with release notes generation.

**Common labels:**
- `feature` - New functionality
- `bugfix` - Bug fixes
- `documentation` - Documentation changes
- `performance` - Performance improvements
- `breaking-change` - Breaking API changes
- `dependencies` - Dependency updates

### Linking Issues

Always link related issues using magic words:

**GitHub issues:**
```markdown
Fixes #123
Refs #456
```

**Linear issues:**
```markdown
Fixes SDK-789
Refs SDK-234
```

**Why magic words matter:**
- `Fixes` automatically closes issue when PR merges
- `Refs` creates bidirectional link without closing
- Enables automatic status updates via GitHub-Linear integration

### Updating Linear

If PR addresses a Linear issue:
1. Include magic word in PR description (`Fixes SDK-123`)
2. Manually add PR link to Linear ticket
3. Update ticket status if needed

This ensures Linear stays in sync with GitHub.

## Review Checklist

Before submitting a PR:

- [ ] Title follows Conventional Commits format
- [ ] Title is under 72 characters
- [ ] Description explains problem and solution clearly
- [ ] Key technical decisions are documented
- [ ] Breaking changes are highlighted (if any)
- [ ] Code examples are included and explained
- [ ] Examples are understandable to SDK users
- [ ] Related issues are linked with magic words
- [ ] GitHub label is applied
- [ ] Linear ticket is updated (if applicable)
- [ ] Follow-up items are documented
- [ ] Description is concise (no file lists or commit history)

## Examples of Good PRs

### Example 1: Feature Addition

**Title:** `feat: add connection pooling to HTTP client`

**Description:**
```markdown
## Problem

The SDK creates a new HTTP connection for every request, leading to
poor performance for applications making multiple sequential queries.
Users report 150ms average latency, with ~50ms spent on connection setup.

## Solution

This PR adds HTTP connection pooling using httpx's built-in capabilities.
The HTTPClient maintains a pool of persistent connections, reusing them
across requests.

## Key Decisions

- **httpx over requests**: Provides sync/async clients with same API
- **Default pool sizes**: 10 keep-alive, 100 max (tunable via config)
- **Context manager support**: Ensures proper connection cleanup
- **Backward compatible**: Enabled by default, no API changes

## Examples

```python
from pinecone import Pinecone

# Pooling enabled by default
pc = Pinecone(api_key="...")
index = pc.Index("example")

# Sequential queries benefit from connection reuse
for i in range(100):
    results = index.query(vector=[0.1] * 128, top_k=10)
```

Connection pooling reduces latency by ~30% for sequential operations.

## Related

- Fixes #145
- Refs SDK-234
- Documentation: [Performance Guide](docs/conventions/performance.md)
```

### Example 2: Bug Fix

**Title:** `fix: validate vector dimensions before upsert`

**Description:**
```markdown
## Problem

The SDK sends invalid vectors to the API without validation, resulting
in cryptic 400 errors from the server. Users struggle to debug dimension
mismatches between their vectors and index configuration.

## Solution

Add client-side validation to check vector dimensions match the index
dimension before making API calls. Provides clear error messages when
dimensions don't match.

## Key Decisions

- **Client-side validation**: Catch errors early with better messages
- **Lazy dimension fetch**: Cache index dimension from describe_index
- **Detailed error**: Include expected vs actual dimensions in message

## Examples

```python
from pinecone import Pinecone

pc = Pinecone(api_key="...")
index = pc.Index("example-index")  # dimension=128

# This now raises a clear error before making API call
try:
    index.upsert([("id1", [0.1] * 64)])  # Wrong dimension!
except ValueError as e:
    print(e)  # "Vector dimension mismatch: expected 128, got 64"
```

## Related

- Fixes #178
- Refs #165 (related validation issue)
```

### Example 3: Breaking Change

**Title:** `feat!: require spec parameter in create_index`

**Description:**
```markdown
## Problem

The API now supports serverless and pod-based deployments, requiring
explicit configuration via the `spec` parameter. The old behavior of
defaulting to pod-based is no longer sufficient.

## Solution

Make `spec` a required parameter in `create_index`. Update all internal
code and examples. Provide migration guide for users.

## Key Decisions

- **Required parameter**: No default to force explicit configuration
- **Two spec types**: Serverless and pod-based, validated at runtime
- **Clear errors**: Validation provides helpful messages for wrong spec

## Breaking Changes

BREAKING CHANGE: The `create_index` method now requires a `spec` parameter to support serverless and pod-based deployments.

### `create_index` now requires `spec` parameter

**Old code:**
```python
pc.create_index(name="my-index", dimension=128)
```

**New code:**
```python
pc.create_index(
    name="my-index",
    dimension=128,
    spec={"serverless": {"cloud": "aws", "region": "us-east-1"}}
)
```

**Impact:** Code without `spec` will raise ValidationError.

**Migration:** See [Migration Guide](docs/migration-guides/v2.md)

## Examples

```python
from pinecone import Pinecone

pc = Pinecone(api_key="...")

# Serverless index
pc.create_index(
    name="serverless-index",
    dimension=128,
    spec={
        "serverless": {
            "cloud": "aws",
            "region": "us-east-1"
        }
    }
)

# Pod-based index
pc.create_index(
    name="pod-index",
    dimension=128,
    spec={
        "pod": {
            "environment": "us-east-1-aws",
            "pod_type": "p1.x1"
        }
    }
)
```

## Related

- Fixes SDK-567
- Migration: [v2.0 Guide](docs/migration-guides/v2.md)
- API Change: [RFC-42](https://github.com/pinecone-io/rfcs/pull/42)
```

## CI Validation

### Automated PR Title Check

The CI pipeline automatically validates PR titles using the `action-semantic-pull-request` GitHub Action. This check:

- ✅ Validates Conventional Commits format (`type: description`)
- ✅ Ensures type is one of: `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `chore`, `ci`
- ✅ Checks that subject starts with lowercase letter
- ✅ Validates breaking change syntax (`type!: description`)
- ❌ Fails the build if title doesn't match

**If the check fails:**
1. Read the error message - it will tell you what's wrong
2. Edit your PR title to match the expected format
3. The check will automatically re-run

**To bypass the check** (rare cases only): Add the `ignore-semantic-pr` label to the PR.

## Tools and Automation

### GitHub CLI

Use `gh` CLI to create PRs:

```bash
# Create PR with title and body
gh pr create \
  --title "feat: add connection pooling" \
  --body "$(cat pr-description.md)" \
  --label "feature"

# Create PR interactively
gh pr create --web
```

### PR Templates

The repository includes a PR template at `.github/pull_request_template.md`
that provides structure. Fill in all sections, removing any that don't apply.

### Cursor `/pr-open` Command

Use the `/pr-open` cursor command for AI-assisted PR creation:

```
/pr-open
```

The AI will:
1. Check git status and recent commits
2. Generate appropriate PR title and description
3. Include code examples
4. Apply proper labels
5. Link related issues

Review and adjust the generated PR before submitting.

## Common Mistakes

❌ **Vague titles:**
```
Update code
Fix issues
Improvements
```

✅ **Specific titles:**
```
feat: add batch upsert support
fix: handle connection timeout in query
perf: reduce memory usage in vector parsing
```

❌ **Missing problem statement:**
```
## Solution
Added connection pooling to the HTTP client.
```

✅ **Clear problem statement:**
```
## Problem
The SDK creates new connections for every request, causing poor performance.

## Solution
Added connection pooling to reuse connections across requests.
```

❌ **No examples:**
```
## Solution
Added support for serverless indexes.

## Related
Fixes #123
```

✅ **With examples:**
```
## Solution
Added support for serverless indexes via spec parameter.

## Examples
```python
pc.create_index(
    name="my-index",
    dimension=128,
    spec={"serverless": {"cloud": "aws", "region": "us-east-1"}}
)
```

## Related
Fixes #123
```

## Summary

Good PRs are permanent documentation linked from release notes. They should:
- **Title:** Conventional Commits format, specific, imperative, <72 chars
- **Description:** Clear explanation of what changed and why it matters to users
- **Examples:** Complete, realistic code that users can copy and adapt to their projects
- **Prose:** Written for SDK users, not just internal developers
- **Breaking Changes:** Include `BREAKING CHANGE:` prefix with clear migration path
- **Metadata:** Proper labels and issue linking
- **Focus:** User impact and practical usage, not internal implementation

Remember: When users read release notes and click your PR link, they should immediately understand:
1. What changed
2. Why it matters to them
3. How to use it (with code examples)
4. How to migrate (if breaking changes)

Write each PR as documentation you'd want to read when learning about a feature.
