Skip to content

Rubric Gap Analysis — New rule needed: partition-immutable-key — No guidance on partition key immutability constraint #47

@jaydestro

Description

@jaydestro

#47 — Rubric Gap Analysis — New rule needed: partition-immutable-key — No guidance on partition key immutability constraint

Field Value
Type New Rule
Proposed Rule partition-immutable-key
Category partition-*
Severity HIGH
Source SCOPE Rubric Criteria — Partition Key Design, Criterion 8 (Immutable PK)
Labels enhancement, SCOPE, agent-kit, rule:partition

Summary

No existing partition-* rule warns that Cosmos DB partition keys are immutable once a document is written. Changing a document's partition key value requires deleting the original document and reinserting it with the new key — a non-atomic two-step operation. Developers from relational backgrounds do not internalize this constraint because SQL databases allow updating any column. Choosing a mutable field (order status, assignment owner, workflow stage) as the partition key leads to escalating application complexity, data integrity bugs, and performance degradation.

Rubric Gap Analysis

During rubric criteria review for partition key design, this was identified as a platform constraint with no corresponding rule file. The existing partition-* rules comprehensively cover cardinality, hotspots, hierarchical keys, query alignment, synthetic keys, key length, and the 20 GB limit — but none mention that the partition key value cannot be updated in place.

The model-id-constraints rule covers the id property constraints but does not address the partition key property. The sdk-spring-data-annotations rule covers @PartitionKey annotation usage but not the immutability behavior.

Evidence

Incorrect Pattern

// Anti-pattern: mutable field as partition key
public class Order
{
    public string Id { get; set; }
    
    // Status changes throughout order lifecycle:
    // "pending" → "processing" → "shipped" → "delivered"
    public string Status { get; set; }  // ❌ Partition key — but it changes!
}

// When order ships, developer tries to "update" the partition key:
order.Status = "shipped";
await container.ReplaceItemAsync(order, order.Id, new PartitionKey("shipped"));
// This does NOT move the document — it either fails or creates corruption
// The document is still in the "pending" partition
// Anti-pattern: ownership field as partition key
@Container(containerName = "tasks")
public class Task {
    @Id
    private String id;
    
    @PartitionKey
    private String assignedTo;  // ❌ Changes when task is reassigned
}

// Reassignment requires delete + reinsert (non-atomic):
container.deleteItem(task.getId(), new PartitionKey("alice"));
task.setAssignedTo("bob");
container.createItem(task, new PartitionKey("bob"));
// If crash occurs between delete and create → data loss

Correct Pattern

// Partition key uses an immutable identifier
public class Order
{
    public string Id { get; set; }
    public string CustomerId { get; set; }  // ✅ Never changes — immutable
    public string Status { get; set; }       // Mutable — but NOT the partition key
}

// Status updates are simple in-place replacements within the same partition:
order.Status = "shipped";
await container.ReplaceItemAsync(order, order.Id, new PartitionKey(order.CustomerId));
// Immutable creation-time value as partition key
@Container(containerName = "tasks")
public class Task {
    @Id
    private String id;
    
    @PartitionKey
    private String projectId;    // ✅ Set at creation, never changes
    
    private String assignedTo;   // Mutable — just a regular property
}

Impact

  • Data integrity: Non-atomic delete+reinsert creates windows for data loss and orphaned documents
  • Application complexity: Teams build increasingly complex "move" patterns that are fragile under failure
  • Silent corruption: Some SDK operations silently succeed without moving the document, leaving it in the wrong partition
  • Unrecoverable: Once mutable-field partition keys are baked into production data, remediation requires full container migration (delete + reinsert all documents)

Recommended New Rule

Create partition-immutable-key.md with the following guidance:

Choose partition key properties whose values never change after document creation.

Cosmos DB partition keys are immutable — you cannot update a document's partition key value in place. Changing the partition key requires deleting the original document and reinserting it with the new key value. This two-step operation is not atomic and introduces failure modes (data loss, orphaned documents, consistency windows).

Never use as partition keys: status fields, workflow stages, ownership/assignment fields, state machine positions, or any property the application updates during the document lifecycle.

Safe partition key choices: entity identifiers (userId, tenantId, deviceId), creation-time values, or synthetic keys derived from immutable fields.

If a partition key change is unavoidable, use TransactionalBatch (same partition) or implement idempotent delete+reinsert with lease/lock patterns to prevent data loss.

References

Metadata

Metadata

Labels

SCOPEIssues generated by SCOPE toolagent-kitIssues requiring updates to cosmosdb-best-practices Agent Kit rulesenhancementNew feature or requestrule:partitionPartition key rules (partition-*)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions