Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Decisions

2026-07-19-category-vs-bucket-are-distinct-axes

Decisioncanonicalverified 2026-07-19

DECISION.2026-07-19.CATEGORY-VS-BUCKET-ARE-DISTINCT-AXES

Category vs Bucket are distinct axes — do not unify

Decision

DocumentRecord.category (VaultCategory, 11 values) and DocumentRecord.bucket (Bucket, 12 values) stay as two independent fields on the document row. They index different things and unifying them would break either the Inbox folder tree or the identity-bucket sidebar.

Why

Two audits flagged the parallel taxonomies as drift; both misread the intent. The two axes serve different queries:

Axis Values Populated by Consumed by
category (VaultCategory) 11 upload-shaped values including identity/liabilities/employment/property Storage-path segment at upload OR user's classify pick Inbox Level-1 folder tree, category-based upload gating
bucket (Bucket) 12 identity-shaped values including retirement/loans/business Derived from identity.type at persist time via bucketOf() 12-bucket Inbox left rail, share scoping, per-bucket year axis

Overlapping values (tax, investments, health, insurance, assets, other) coincidentally mean the same thing. Non-overlapping values (identity vs identity_documents, liabilities vs loans, employment vs employer, property (missing in Bucket) vs retirement/business (missing in VaultCategory)) reflect the different framings — an upload starts as a folder-tree category before we know its identity, and lands in an identity-bucket after the matcher runs.

Unifying them would force one of:

  • Delete identity / liabilities / employment / property — breaks the upload flow (these are pre-identity categories used when the user picks a folder before any parsing).
  • Delete retirement / loans / business — breaks the 12-bucket wiki entity + Inbox left rail.
  • Redefine every value to the identity meaning — breaks upload gating (a user picking "Loans" at upload time doesn't have a loan identity yet).

Impact

  • bucket is now typed as BucketSchema.nullable().optional() on DocumentRecordSchema (was z.string()). The 12 canonical values are enforced at Zod parse time.
  • category stays as z.string().default("other") because the storage-path segment can carry legacy values on old rows.
  • Sync-check tooling should NOT flag "code has 11 categories, wiki has 12 buckets" — the discrepancy is by design.

Status

Active. Log any future proposal to unify them by appending here with supersedes: [DECISION.2026-07-19.CATEGORY-VS-BUCKET-ARE-DISTINCT-AXES].

Sources

  • Audit report 2026-07-19 (Schema layer §7)
  • packages/shared/src/schemas/document.ts — VAULT_CATEGORIES + DocumentRecordSchema.bucket
  • packages/shared/src/schemas/buckets.ts — BUCKETS + bucketOf
  • .context/wiki/entities/identity-buckets.md — the 12-bucket source of truth

Every project of mine is written down like this.

Read the résumé