Skip to content

chore(schema): canonical remediation — chitty_id, P/L/T/E/A, entities registry, R2 ACL#34

Open
chitcommit wants to merge 1 commit into
feat/hono-migration-phase-1from
chore/schema-canonical-remediation
Open

chore(schema): canonical remediation — chitty_id, P/L/T/E/A, entities registry, R2 ACL#34
chitcommit wants to merge 1 commit into
feat/hono-migration-phase-1from
chore/schema-canonical-remediation

Conversation

@chitcommit
Copy link
Copy Markdown
Contributor

Summary

Greenfield canonical schema for Neon project steep-cloud-28172078. The database was empty pre-migration (confirmed via get_database_tables[]), so no production data preservation needed. Stacked on feat/hono-migration-phase-1 since canonical docs (CHARTER/CHITTY/register.json) and the Worker skeleton live there — merging to main direct would conflict.

  • 3 migrations in drizzle/ establishing the canonical baseline: chitty_id varchar UNIQUE on every entity table, timestamptz created_at/updated_at with shared set_updated_at trigger, soft-delete deleted_at, GIN indexes on JSONB, and the entities registry with entity_type enum containing ALL FIVE P/L/T/E/A values.
  • shared/schema.ts rewritten to mirror DDL with // @canon: chittycanon://gov/governance#core-types annotations on every entity_type-bearing table.
  • Phase 3 plan documented (docs/migrations/phase3-users-chittyid-migration.md) — 5-step backward-compatible promotion of users.chitty_id to PK. Not executed in this PR.

Entity-type assignments (annotated per table)

Table Type Rationale
users P Natural actor with agency (canonical rule: actors are always Person, never Thing)
assets T Object without agency — the central ChittyAssets artifact
evidence T Document/artifact attached to an asset
timeline_events E Append-only occurrence in time
warranties T Contract-as-artifact (the document); coverage events go in timeline_events
insurance_policies T Policy document as artifact; claims go in timeline_events
legal_cases E Proceeding with docket/status progression
ai_analysis_results E Analysis run in time, append-only

sessions (legacy Replit Auth) and r2_object_acl (operational metadata) are not canonical entities and correctly lack chitty_id.

Soft references

Per-service tables do NOT FK to the entities registry. The registry is populated by app-layer triggers / batch reconciliation. Schema authority remains per-table.

Validation evidence (Neon preview branch br-spring-star-aky6u1mc)

All 63 DDL statements executed cleanly via run_sql_transaction. Read-back queries on the preview branch confirm:

  • 11 tables present: ai_analysis_results, assets, entities, evidence, insurance_policies, legal_cases, r2_object_acl, sessions, timeline_events, users, warranties
  • Every entity table has chitty_id UNIQUE + created_at timestamptz
  • entity_type enum values = {P, L, T, E, A} — all five canonical types, A not omitted
  • npm run check: zero errors in shared/schema.ts (pre-existing errors in legacy server/chittyCore.ts, server/chittyEcosystem.ts, client/__tests__/* are unrelated to this PR)

Test plan

  • Neon GitHub integration auto-spawns preview branch on this PR
  • Run npm run db:push against preview DATABASE_URL to confirm Drizzle reconciliation against DDL is a no-op
  • Verify entity_type enum on preview is {P,L,T,E,A} exactly
  • Confirm zero shared/schema.ts errors in npm run check
  • After merge of feat/hono-migration-phase-1 → main, re-target this PR to main if needed

Out of scope

  • Phase 3 users.id uuid → chitty_id PK migration (documented in docs/migrations/phase3-users-chittyid-migration.md)
  • Rewriting legacy mock-based integration tests (global rule: pre-existing mocked tests may remain untouched)
  • Fixing pre-existing typecheck errors in server/chittyCore.ts etc.

🤖 Generated with Claude Code

… registry, R2 ACL

Greenfield canonical schema for Neon project steep-cloud-28172078. The DB was
empty pre-migration; no production data to preserve. Stacked on Phase 1 Hono
branch since canonical docs and Worker skeleton live there.

Migrations (drizzle/):
- 0001_init.sql — Drop-in canonical baseline. All entity tables get nullable
  chitty_id varchar UNIQUE, timestamptz created_at/updated_at, soft-delete
  deleted_at where applicable, GIN indexes on JSONB, and a shared
  set_updated_at trigger. Entity-type assignments annotated per table:
  users=P, assets=T, evidence=T, timeline_events=E, warranties=T,
  insurance_policies=T, legal_cases=E, ai_analysis_results=E. Borderline
  calls documented in COMMENT ON TABLE with canonical rationale.
- 0002_entities_registry.sql — Canonical discovery/audit index with
  entity_type enum containing ALL FIVE P/L/T/E/A values (never omit A).
  Soft references only: per-service tables do NOT FK here.
- 0003_r2_object_acl.sql — Replaces GCS objectStorage.ts ACL with a
  Neon-backed table. principal_chitty_id is a Person (P); evidence_id /
  asset_id scope grants to Thing (T) artifacts.

docs/migrations/phase3-users-chittyid-migration.md — 5-step plan to promote
users.chitty_id to PK once ChittyAuth-only cutover completes. Document only,
not executed in this PR.

shared/schema.ts — Rewritten to mirror DDL. All entity_type-bearing tables
carry // @canon: chittycanon://gov/governance#core-types annotations.
CANONICAL_ENTITY_TYPES tuple and CHITTY_ID_PATTERN regex include all
five P/L/T/E/A; never omit A.

Validated on Neon preview branch br-spring-star-aky6u1mc:
- All 63 DDL statements executed cleanly via run_sql_transaction
- Read-back confirms 11 tables, every entity table has chitty_id +
  created_at, entity_type enum = {P,L,T,E,A}
- npm run check: zero shared/schema.ts errors (pre-existing errors in
  legacy server/* and client/* are unrelated)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4584f6ab-f275-488d-96c1-bf017ecab970

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/schema-canonical-remediation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7010f01fef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread shared/schema.ts
Comment on lines +284 to 297
export const r2ObjectAcl = pgTable('r2_object_acl', {
id: varchar('id').primaryKey().default(sql`gen_random_uuid()`),
bucket: varchar('bucket').notNull(),
objectKey: text('object_key').notNull(),
/** Person (P) ChittyID — soft ref to users.chitty_id. */
principalChittyId: varchar('principal_chitty_id').notNull(),
permission: r2AclPermissionEnum('permission').notNull(),
grantedByChittyId: varchar('granted_by_chitty_id'),
evidenceId: varchar('evidence_id').references(() => evidence.id),
assetId: varchar('asset_id').references(() => assets.id),
expiresAt: timestamp('expires_at', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
revokedAt: timestamp('revoked_at', { withTimezone: true }),
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Mirror ACL uniqueness in Drizzle schema

The new r2_object_acl table is missing the composite uniqueness constraint that exists in drizzle/0003_r2_object_acl.sql (UNIQUE (bucket, object_key, principal_chitty_id, permission)). Because this repo’s normal workflow uses npm run db:push from shared/schema.ts, environments bootstrapped from schema (or reconciled by push) can end up without that guard and accept duplicate grants for the same principal/object/permission tuple, which can make permission resolution ambiguous and break idempotent grant logic.

Useful? React with 👍 / 👎.

Comment thread shared/schema.ts
Comment on lines +95 to +101
export const assets = pgTable('assets', {
id: varchar('id').primaryKey().default(sql`gen_random_uuid()`),
/** Canonical Thing ChittyID. Format VV-G-LLL-SSSS-T-YM-C-X. */
chittyId: varchar('chitty_id').unique(),
chittyIdV2: varchar('chitty_id_v2').unique(),
userId: varchar('user_id').notNull().references(() => users.id),
name: text('name').notNull(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Define assets user_id index in schema source of truth

drizzle/0001_init.sql adds idx_assets_user_id, but shared/schema.ts does not define an index for assets.user_id; since this project deploys schema changes via drizzle-kit push (from shared/schema.ts), that index will not be created (or can be removed on reconciliation), causing user-scoped asset reads (getAsset, getUserAssets, getAssetStats) to degrade into increasingly expensive scans as asset volume grows.

Useful? React with 👍 / 👎.

Comment thread shared/schema.ts
Comment on lines +133 to +137
export const evidence = pgTable('evidence', {
id: varchar('id').primaryKey().default(sql`gen_random_uuid()`),
chittyId: varchar('chitty_id').unique(),
assetId: varchar('asset_id').notNull().references(() => assets.id),
userId: varchar('user_id').notNull().references(() => users.id),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve evidence lookup indexes in Drizzle schema

The SQL migration creates idx_evidence_asset_id and idx_evidence_user_id, but shared/schema.ts does not declare either index for evidence; with drizzle-kit push using the schema file as source of truth, environments can miss these indexes and turn /api/assets/:assetId/evidence and per-user evidence reads into table scans as evidence volume increases.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant