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-AXESCategory 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
bucketis now typed asBucketSchema.nullable().optional()onDocumentRecordSchema(wasz.string()). The 12 canonical values are enforced at Zod parse time.categorystays asz.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é