# Pathrule Pattern: gRPC and Protocol Buffers (1.0.0)
# ::pathrule:package:grpc-protobuf

### [RULE] Evolve Protobuf schemas without changing wire meaning  (path: /proto)
<!-- scope: folder | priority: high | strict -->

Generated code hides the wire format, but deployed clients, stored messages, and queued payloads may retain old field numbers for years. Reusing one makes old bytes decode as a different concept.

- Reserve the names and numbers of removed fields and enum values so future authors cannot assign them accidentally.
- Add fields with safe absence behavior and avoid changing a field's type, repetition, or semantic meaning under the same number.
- Keep enum zero as a deliberate unspecified value and make receivers handle values newer than their generated code.
- Introduce a new message, method, or service version for incompatible required semantics instead of relying on coordinated fleet deployment.

See /tests/contract for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Propagate deadlines and cancellation through every downstream call  (path: /src/grpc)
<!-- scope: folder | priority: high | strict -->

Without a deadline, an RPC can occupy threads, streams, connections, and database work indefinitely. A service that ignores cancellation also wastes capacity after its caller has already timed out.

- Set client deadlines from the product operation budget and reject unbounded internal calls at the service boundary.
- Propagate the remaining deadline to downstream RPC, database, and external work while reserving time for local cleanup and response serialization.
- Observe cancellation in handlers and streaming loops, release resources promptly, and do not continue optional work merely because a goroutine or promise is still running.
- Design commit points so cancellation before commit aborts and cancellation after commit returns or reconciles a stable operation outcome.

See /src/grpc for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Retry only idempotent RPC outcomes under an explicit policy  (path: /src/grpc)
<!-- scope: folder | priority: high | strict -->

A transport failure or unavailable status does not always prove the server did no work. Retrying a mutation can duplicate the effect unless the application recognizes the same logical request.

- Mark read-only or idempotent methods explicitly in client policy and leave state-changing methods without automatic retry unless they use an idempotency key.
- Retry only selected transient statuses before the overall deadline and stop after bounded attempts with jitter.
- Do not retry validation, authentication, authorization, failed precondition, conflict, or unsupported-operation outcomes.
- Include a stable operation identity in state-changing requests and make the server return the prior result after ambiguous client retry.

See /tests/contract for the adjacent decision or procedure that completes this constraint.

---

### [MEMORY] Status codes carry stable public failure semantics  (path: /src/grpc)

Returning UNKNOWN or INTERNAL for every expected failure prevents clients from deciding whether to correct input, refresh identity, resolve conflict, or retry later.

- Use invalid-argument for malformed values, failed-precondition for unmet state, not-found for absent authorized resources, and permission outcomes without revealing hidden resources.
- Reserve unavailable and resource-exhausted for transient service or capacity conditions callers may handle under policy.
- Attach structured error details only when clients have a contract to consume them and keep metadata within bounded size.
- Log internal causes with correlation identity while returning a stable public message that excludes secrets, stack traces, SQL, and dependency internals.

See /proto for the rule or workflow that puts this decision into practice.

---

### [MEMORY] Streaming handlers own backpressure and half-close behavior  (path: /src/grpc)

HTTP/2 provides transport flow control, but application code can defeat it by reading an entire stream into memory or producing into an unbounded queue before writes complete.

- Process incoming messages incrementally with limits on count, bytes, concurrency, and per-message cost.
- Wait for outbound write readiness or completion rather than appending indefinitely to an application buffer.
- Define what client half-close means, when the server may finish, and whether partial results are valid after an error.
- Stop producer and consumer work together on cancellation or stream failure so one side does not leak after the other exits.

See /tests/contract for the rule or workflow that puts this decision into practice.

---

### [MEMORY] Field presence is a business decision  (path: /proto)

Protobuf scalar defaults can make an absent value look like an explicit zero or empty string. Patch and configuration APIs often need to distinguish those states.

- Model optional input with presence when omission means leave unchanged and an explicit default means set or clear.
- Use a field mask or command-specific patch message for partial updates rather than interpreting every default as missing.
- Keep output defaults semantically valid so older clients can tolerate newly absent or unknown data.
- Test generated clients in every supported language because presence and JSON mapping ergonomics differ even when the wire behavior is compatible.

See /src/grpc for the rule or workflow that puts this decision into practice.

---

### [SKILL] review-grpc-contract  (path: /)

---
name: review-grpc-contract
description: Review a gRPC service or Protobuf change before publishing generated artifacts or deploying servers.
---

# Review Grpc Contract

Run this procedure when the affected surface changes, before the result is promoted to production. Record evidence for every step instead of accepting a plausible-looking result.

1. Run schema compatibility checks against the released descriptor set and inspect every changed number, name, type, enum, oneof, and presence rule.
2. Generate supported clients and compile representative callers, including older clients against the new server and new clients against the old server.
3. Exercise deadline expiry, cancellation, authentication, authorization, validation, conflict, capacity, and dependency failure and verify status semantics.
4. Test retry policy with ambiguous state-changing outcomes and stable operation identity; prove no method retries beyond the caller's deadline.
5. For streams, test slow readers, slow writers, half-close, large messages, cancellation, server restart, and bounded memory under sustained flow.

## Exit criteria

The change is complete only when the expected behavior, failure behavior, and rollback path have all been exercised with representative data. Preserve the evidence with the change so the next operator can repeat the same checks.
