diff --git a/drizzle/0014_wandering_owl.sql b/drizzle/0014_wandering_owl.sql new file mode 100644 index 0000000..357dcdf --- /dev/null +++ b/drizzle/0014_wandering_owl.sql @@ -0,0 +1,5 @@ +CREATE TABLE `quilt_wal_lock` ( + `id` integer PRIMARY KEY NOT NULL, + `holder` text NOT NULL, + `acquired_at` text NOT NULL +); diff --git a/drizzle/meta/0013_snapshot.json b/drizzle/meta/0013_snapshot.json new file mode 100644 index 0000000..24a59e3 --- /dev/null +++ b/drizzle/meta/0013_snapshot.json @@ -0,0 +1,2101 @@ +{ + "id": "cdf4c842-74f4-4148-b252-97eb684e042c", + "prevId": "30731fe5-aff9-413c-b7c6-cbe4ac734ebc", + "version": "6", + "dialect": "sqlite", + "tables": { + "action_cooldown_events": { + "name": "action_cooldown_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "interaction_id": { + "name": "interaction_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action_kind": { + "name": "action_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_expires_at": { + "name": "actor_expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_expires_at": { + "name": "target_expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_expires_at": { + "name": "channel_expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "action_cooldown_events_interaction_id_unique": { + "name": "action_cooldown_events_interaction_id_unique", + "columns": [ + "interaction_id" + ], + "isUnique": true + }, + "idx_action_cooldowns_actor": { + "name": "idx_action_cooldowns_actor", + "columns": [ + "guild_id", + "actor_id", + "actor_expires_at" + ], + "isUnique": false + }, + "idx_action_cooldowns_target": { + "name": "idx_action_cooldowns_target", + "columns": [ + "guild_id", + "target_id", + "target_expires_at" + ], + "isUnique": false + }, + "idx_action_cooldowns_channel": { + "name": "idx_action_cooldowns_channel", + "columns": [ + "guild_id", + "channel_id", + "channel_expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "claim_requests": { + "name": "claim_requests", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "github_username": { + "name": "github_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "merged_pr_count": { + "name": "merged_pr_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "review_message_id": { + "name": "review_message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "review_thread_id": { + "name": "review_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_at": { + "name": "decided_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_by_id": { + "name": "decided_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decision_reason": { + "name": "decision_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_claim_requests_guild_user": { + "name": "idx_claim_requests_guild_user", + "columns": [ + "guild_id", + "user_id" + ], + "isUnique": true + }, + "idx_claim_requests_user_id": { + "name": "idx_claim_requests_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "idx_claim_requests_status": { + "name": "idx_claim_requests_status", + "columns": [ + "status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clawhub_content_rights_cases": { + "name": "clawhub_content_rights_cases", + "columns": { + "case_id": { + "name": "case_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "form_submission_id": { + "name": "form_submission_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "requester_name": { + "name": "requester_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization": { + "name": "organization", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "clawhub_urls": { + "name": "clawhub_urls", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "explanation": { + "name": "explanation", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "clawhub_content_rights_cases_form_submission_id_unique": { + "name": "clawhub_content_rights_cases_form_submission_id_unique", + "columns": [ + "form_submission_id" + ], + "isUnique": true + }, + "idx_clawhub_content_rights_cases_status": { + "name": "idx_clawhub_content_rights_cases_status", + "columns": [ + "status" + ], + "isUnique": false + }, + "idx_clawhub_content_rights_cases_email": { + "name": "idx_clawhub_content_rights_cases_email", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clawhub_content_rights_events": { + "name": "clawhub_content_rights_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "case_id": { + "name": "case_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor": { + "name": "actor", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_clawhub_content_rights_events_case_id": { + "name": "idx_clawhub_content_rights_events_case_id", + "columns": [ + "case_id" + ], + "isUnique": false + }, + "idx_clawhub_content_rights_events_event_type": { + "name": "idx_clawhub_content_rights_events_event_type", + "columns": [ + "event_type" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clawhub_content_rights_files": { + "name": "clawhub_content_rights_files", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "case_id": { + "name": "case_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "object_key": { + "name": "object_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_bytes": { + "name": "size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sha256": { + "name": "sha256", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "clawhub_content_rights_files_object_key_unique": { + "name": "clawhub_content_rights_files_object_key_unique", + "columns": [ + "object_key" + ], + "isUnique": true + }, + "idx_clawhub_content_rights_files_case_id": { + "name": "idx_clawhub_content_rights_files_case_id", + "columns": [ + "case_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "form_submissions": { + "name": "form_submissions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "form_id": { + "name": "form_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "auth_provider": { + "name": "auth_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "applicant_id": { + "name": "applicant_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "applicant_username": { + "name": "applicant_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "review_channel_id": { + "name": "review_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "review_message_id": { + "name": "review_message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "review_thread_id": { + "name": "review_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_at": { + "name": "decided_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_by_id": { + "name": "decided_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decision_reason": { + "name": "decision_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action_result": { + "name": "action_result", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_form_submissions_form_id": { + "name": "idx_form_submissions_form_id", + "columns": [ + "form_id" + ], + "isUnique": false + }, + "idx_form_submissions_status": { + "name": "idx_form_submissions_status", + "columns": [ + "status" + ], + "isUnique": false + }, + "idx_form_submissions_applicant_id": { + "name": "idx_form_submissions_applicant_id", + "columns": [ + "applicant_id" + ], + "isUnique": false + }, + "idx_form_submissions_review_message_id": { + "name": "idx_form_submissions_review_message_id", + "columns": [ + "review_message_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "helper_events": { + "name": "helper_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'helper_command'" + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "message_count": { + "name": "message_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "event_time": { + "name": "event_time", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invoked_by_id": { + "name": "invoked_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invoked_by_username": { + "name": "invoked_by_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invoked_by_global_name": { + "name": "invoked_by_global_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "received_at": { + "name": "received_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_helper_events_event_time": { + "name": "idx_helper_events_event_time", + "columns": [ + "event_time" + ], + "isUnique": false + }, + "idx_helper_events_command": { + "name": "idx_helper_events_command", + "columns": [ + "command" + ], + "isUnique": false + }, + "idx_helper_events_thread_id": { + "name": "idx_helper_events_thread_id", + "columns": [ + "thread_id" + ], + "isUnique": false + }, + "idx_helper_events_invoked_by_id": { + "name": "idx_helper_events_invoked_by_id", + "columns": [ + "invoked_by_id" + ], + "isUnique": false + }, + "idx_helper_events_event_type": { + "name": "idx_helper_events_event_type", + "columns": [ + "event_type" + ], + "isUnique": false + }, + "idx_helper_events_thread_time": { + "name": "idx_helper_events_thread_time", + "columns": [ + "thread_id", + "event_time" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "keyValue": { + "name": "keyValue", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "lobster_encounters": { + "name": "lobster_encounters", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "interaction_id": { + "name": "interaction_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cooldown_event_id": { + "name": "cooldown_event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_is_bot": { + "name": "target_is_bot", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "taxonomy_snapshot_id": { + "name": "taxonomy_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_aphia_id": { + "name": "species_aphia_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_accepted_name": { + "name": "species_accepted_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_display_name": { + "name": "species_display_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_family": { + "name": "species_family", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scene_id": { + "name": "scene_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "asset_url": { + "name": "asset_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "asset_checksum": { + "name": "asset_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "headline": { + "name": "headline", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "narrative": { + "name": "narrative", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metrics_json": { + "name": "metrics_json", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "accessibility_description": { + "name": "accessibility_description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "publication_status": { + "name": "publication_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "publication_failure": { + "name": "publication_failure", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "publication_failed_at": { + "name": "publication_failed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "message_bound_at": { + "name": "message_bound_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_status": { + "name": "response_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "response_type": { + "name": "response_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_actor_id": { + "name": "response_actor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "responded_at": { + "name": "responded_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_result_json": { + "name": "response_result_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_actor_id": { + "name": "counter_actor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_target_id": { + "name": "counter_target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_scene_id": { + "name": "counter_scene_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_asset_url": { + "name": "counter_asset_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_asset_checksum": { + "name": "counter_asset_checksum", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_headline": { + "name": "counter_headline", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_narrative": { + "name": "counter_narrative", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_metrics_json": { + "name": "counter_metrics_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_accessibility_description": { + "name": "counter_accessibility_description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "lobster_encounters_interaction_id_unique": { + "name": "lobster_encounters_interaction_id_unique", + "columns": [ + "interaction_id" + ], + "isUnique": true + }, + "lobster_encounters_cooldown_event_id_unique": { + "name": "lobster_encounters_cooldown_event_id_unique", + "columns": [ + "cooldown_event_id" + ], + "isUnique": true + }, + "idx_lobster_encounters_message": { + "name": "idx_lobster_encounters_message", + "columns": [ + "guild_id", + "channel_id", + "message_id" + ], + "isUnique": false + }, + "idx_lobster_encounters_species": { + "name": "idx_lobster_encounters_species", + "columns": [ + "species_aphia_id" + ], + "isUnique": false + }, + "idx_lobster_encounters_publication": { + "name": "idx_lobster_encounters_publication", + "columns": [ + "publication_status" + ], + "isUnique": false + }, + "idx_lobster_encounters_response": { + "name": "idx_lobster_encounters_response", + "columns": [ + "response_status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "nomination_approvals": { + "name": "nomination_approvals", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "nomination_id": { + "name": "nomination_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "approver_id": { + "name": "approver_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "vote_choice": { + "name": "vote_choice", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'approve'" + }, + "mutation_id": { + "name": "mutation_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_nomination_approvals_nomination_approver": { + "name": "idx_nomination_approvals_nomination_approver", + "columns": [ + "nomination_id", + "approver_id" + ], + "isUnique": true + }, + "idx_nomination_approvals_nomination_id": { + "name": "idx_nomination_approvals_nomination_id", + "columns": [ + "nomination_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "nominations": { + "name": "nominations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nominee_id": { + "name": "nominee_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nominator_id": { + "name": "nominator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'No reason provided.'" + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_role_id": { + "name": "target_role_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "required_approvals": { + "name": "required_approvals", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "desired_card_revision": { + "name": "desired_card_revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "synced_card_revision": { + "name": "synced_card_revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "card_sync_started_at": { + "name": "card_sync_started_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_sync_failure_count": { + "name": "card_sync_failure_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "grant_started_at": { + "name": "grant_started_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "grant_failure_count": { + "name": "grant_failure_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_nominations_active_unique": { + "name": "idx_nominations_active_unique", + "columns": [ + "guild_id", + "nominee_id", + "target_role_id" + ], + "where": "\"nominations\".\"status\" in ('submitted', 'granting')", + "isUnique": true + }, + "idx_nominations_status": { + "name": "idx_nominations_status", + "columns": [ + "status" + ], + "isUnique": false + }, + "idx_nominations_card_sync": { + "name": "idx_nominations_card_sync", + "columns": [ + "desired_card_revision", + "synced_card_revision" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "reddit_moderation_contexts": { + "name": "reddit_moderation_contexts", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "subreddit": { + "name": "subreddit", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'moderated'" + }, + "unaction": { + "name": "unaction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'reviewed'" + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "moderator": { + "name": "moderator", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "banned_at": { + "name": "banned_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_reddit_moderation_contexts_subreddit_username": { + "name": "idx_reddit_moderation_contexts_subreddit_username", + "columns": [ + "subreddit", + "username" + ], + "isUnique": true + }, + "idx_reddit_moderation_contexts_username": { + "name": "idx_reddit_moderation_contexts_username", + "columns": [ + "username" + ], + "isUnique": false + }, + "idx_reddit_moderation_contexts_action": { + "name": "idx_reddit_moderation_contexts_action", + "columns": [ + "action" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "slap_events": { + "name": "slap_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "interaction_id": { + "name": "interaction_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_is_bot": { + "name": "target_is_bot", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "fish_slug": { + "name": "fish_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fish_name": { + "name": "fish_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rarity": { + "name": "rarity", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "headline": { + "name": "headline", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "narrative": { + "name": "narrative", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impact": { + "name": "impact", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dignity_remaining": { + "name": "dignity_remaining", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fish_condition": { + "name": "fish_condition", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "counter_actor_id": { + "name": "counter_actor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_target_id": { + "name": "counter_target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_fish_slug": { + "name": "counter_fish_slug", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_fish_name": { + "name": "counter_fish_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_rarity": { + "name": "counter_rarity", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_outcome": { + "name": "counter_outcome", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_headline": { + "name": "counter_headline", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_narrative": { + "name": "counter_narrative", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_impact": { + "name": "counter_impact", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_dignity_remaining": { + "name": "counter_dignity_remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_fish_condition": { + "name": "counter_fish_condition", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_image_url": { + "name": "counter_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "countered_at": { + "name": "countered_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appealed_by_id": { + "name": "appealed_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appeal_ruling": { + "name": "appeal_ruling", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appealed_at": { + "name": "appealed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "slap_events_interaction_id_unique": { + "name": "slap_events_interaction_id_unique", + "columns": [ + "interaction_id" + ], + "isUnique": true + }, + "idx_slap_events_actor_cooldown": { + "name": "idx_slap_events_actor_cooldown", + "columns": [ + "guild_id", + "actor_id", + "created_at" + ], + "isUnique": false + }, + "idx_slap_events_target_cooldown": { + "name": "idx_slap_events_target_cooldown", + "columns": [ + "guild_id", + "target_id", + "created_at" + ], + "isUnique": false + }, + "idx_slap_events_channel_cooldown": { + "name": "idx_slap_events_channel_cooldown", + "columns": [ + "guild_id", + "channel_id", + "created_at" + ], + "isUnique": false + }, + "idx_slap_events_message": { + "name": "idx_slap_events_message", + "columns": [ + "guild_id", + "channel_id", + "message_id" + ], + "isUnique": false + }, + "idx_slap_events_outcome": { + "name": "idx_slap_events_outcome", + "columns": [ + "outcome" + ], + "isUnique": false + }, + "idx_slap_events_rarity": { + "name": "idx_slap_events_rarity", + "columns": [ + "rarity" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tracked_threads": { + "name": "tracked_threads", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_checked": { + "name": "last_checked", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "solved": { + "name": "solved", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "warning_level": { + "name": "warning_level", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "closed": { + "name": "closed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_message_count": { + "name": "last_message_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "received_at": { + "name": "received_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "tracked_threads_thread_id_unique": { + "name": "tracked_threads_thread_id_unique", + "columns": [ + "thread_id" + ], + "isUnique": true + }, + "idx_tracked_threads_solved": { + "name": "idx_tracked_threads_solved", + "columns": [ + "solved" + ], + "isUnique": false + }, + "idx_tracked_threads_last_checked": { + "name": "idx_tracked_threads_last_checked", + "columns": [ + "last_checked" + ], + "isUnique": false + }, + "idx_tracked_threads_received_at": { + "name": "idx_tracked_threads_received_at", + "columns": [ + "received_at" + ], + "isUnique": false + }, + "idx_tracked_threads_closed": { + "name": "idx_tracked_threads_closed", + "columns": [ + "closed" + ], + "isUnique": false + }, + "idx_tracked_threads_warning_level": { + "name": "idx_tracked_threads_warning_level", + "columns": [ + "warning_level" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "quilt_wal": { + "name": "quilt_wal", + "columns": { + "seq": { + "name": "seq", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "mutation_id": { + "name": "mutation_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ts": { + "name": "ts", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cell": { + "name": "cell", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "op": { + "name": "op", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prev_hash": { + "name": "prev_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "quilt_wal_mutation_idx": { + "name": "quilt_wal_mutation_idx", + "columns": [ + "mutation_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0014_snapshot.json b/drizzle/meta/0014_snapshot.json new file mode 100644 index 0000000..4ba8e49 --- /dev/null +++ b/drizzle/meta/0014_snapshot.json @@ -0,0 +1,2132 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "0079cbb5-f850-4f68-8704-7f5314ef2c48", + "prevId": "cdf4c842-74f4-4148-b252-97eb684e042c", + "tables": { + "action_cooldown_events": { + "name": "action_cooldown_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "interaction_id": { + "name": "interaction_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action_kind": { + "name": "action_kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor_expires_at": { + "name": "actor_expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_expires_at": { + "name": "target_expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_expires_at": { + "name": "channel_expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "action_cooldown_events_interaction_id_unique": { + "name": "action_cooldown_events_interaction_id_unique", + "columns": [ + "interaction_id" + ], + "isUnique": true + }, + "idx_action_cooldowns_actor": { + "name": "idx_action_cooldowns_actor", + "columns": [ + "guild_id", + "actor_id", + "actor_expires_at" + ], + "isUnique": false + }, + "idx_action_cooldowns_target": { + "name": "idx_action_cooldowns_target", + "columns": [ + "guild_id", + "target_id", + "target_expires_at" + ], + "isUnique": false + }, + "idx_action_cooldowns_channel": { + "name": "idx_action_cooldowns_channel", + "columns": [ + "guild_id", + "channel_id", + "channel_expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "claim_requests": { + "name": "claim_requests", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "github_username": { + "name": "github_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "merged_pr_count": { + "name": "merged_pr_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "review_message_id": { + "name": "review_message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "review_thread_id": { + "name": "review_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_at": { + "name": "decided_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_by_id": { + "name": "decided_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decision_reason": { + "name": "decision_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_claim_requests_guild_user": { + "name": "idx_claim_requests_guild_user", + "columns": [ + "guild_id", + "user_id" + ], + "isUnique": true + }, + "idx_claim_requests_user_id": { + "name": "idx_claim_requests_user_id", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "idx_claim_requests_status": { + "name": "idx_claim_requests_status", + "columns": [ + "status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clawhub_content_rights_cases": { + "name": "clawhub_content_rights_cases", + "columns": { + "case_id": { + "name": "case_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "form_submission_id": { + "name": "form_submission_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "requester_name": { + "name": "requester_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization": { + "name": "organization", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "clawhub_urls": { + "name": "clawhub_urls", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "explanation": { + "name": "explanation", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "clawhub_content_rights_cases_form_submission_id_unique": { + "name": "clawhub_content_rights_cases_form_submission_id_unique", + "columns": [ + "form_submission_id" + ], + "isUnique": true + }, + "idx_clawhub_content_rights_cases_status": { + "name": "idx_clawhub_content_rights_cases_status", + "columns": [ + "status" + ], + "isUnique": false + }, + "idx_clawhub_content_rights_cases_email": { + "name": "idx_clawhub_content_rights_cases_email", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clawhub_content_rights_events": { + "name": "clawhub_content_rights_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "case_id": { + "name": "case_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "actor": { + "name": "actor", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_clawhub_content_rights_events_case_id": { + "name": "idx_clawhub_content_rights_events_case_id", + "columns": [ + "case_id" + ], + "isUnique": false + }, + "idx_clawhub_content_rights_events_event_type": { + "name": "idx_clawhub_content_rights_events_event_type", + "columns": [ + "event_type" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "clawhub_content_rights_files": { + "name": "clawhub_content_rights_files", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "case_id": { + "name": "case_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "object_key": { + "name": "object_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size_bytes": { + "name": "size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sha256": { + "name": "sha256", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "clawhub_content_rights_files_object_key_unique": { + "name": "clawhub_content_rights_files_object_key_unique", + "columns": [ + "object_key" + ], + "isUnique": true + }, + "idx_clawhub_content_rights_files_case_id": { + "name": "idx_clawhub_content_rights_files_case_id", + "columns": [ + "case_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "form_submissions": { + "name": "form_submissions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "form_id": { + "name": "form_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "auth_provider": { + "name": "auth_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "applicant_id": { + "name": "applicant_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "applicant_username": { + "name": "applicant_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "review_channel_id": { + "name": "review_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "review_message_id": { + "name": "review_message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "review_thread_id": { + "name": "review_thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_at": { + "name": "decided_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decided_by_id": { + "name": "decided_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "decision_reason": { + "name": "decision_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action_result": { + "name": "action_result", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_form_submissions_form_id": { + "name": "idx_form_submissions_form_id", + "columns": [ + "form_id" + ], + "isUnique": false + }, + "idx_form_submissions_status": { + "name": "idx_form_submissions_status", + "columns": [ + "status" + ], + "isUnique": false + }, + "idx_form_submissions_applicant_id": { + "name": "idx_form_submissions_applicant_id", + "columns": [ + "applicant_id" + ], + "isUnique": false + }, + "idx_form_submissions_review_message_id": { + "name": "idx_form_submissions_review_message_id", + "columns": [ + "review_message_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "helper_events": { + "name": "helper_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'helper_command'" + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "message_count": { + "name": "message_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "event_time": { + "name": "event_time", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invoked_by_id": { + "name": "invoked_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invoked_by_username": { + "name": "invoked_by_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invoked_by_global_name": { + "name": "invoked_by_global_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "received_at": { + "name": "received_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_helper_events_event_time": { + "name": "idx_helper_events_event_time", + "columns": [ + "event_time" + ], + "isUnique": false + }, + "idx_helper_events_command": { + "name": "idx_helper_events_command", + "columns": [ + "command" + ], + "isUnique": false + }, + "idx_helper_events_thread_id": { + "name": "idx_helper_events_thread_id", + "columns": [ + "thread_id" + ], + "isUnique": false + }, + "idx_helper_events_invoked_by_id": { + "name": "idx_helper_events_invoked_by_id", + "columns": [ + "invoked_by_id" + ], + "isUnique": false + }, + "idx_helper_events_event_type": { + "name": "idx_helper_events_event_type", + "columns": [ + "event_type" + ], + "isUnique": false + }, + "idx_helper_events_thread_time": { + "name": "idx_helper_events_thread_time", + "columns": [ + "thread_id", + "event_time" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "keyValue": { + "name": "keyValue", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updatedAt": { + "name": "updatedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "lobster_encounters": { + "name": "lobster_encounters", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "interaction_id": { + "name": "interaction_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cooldown_event_id": { + "name": "cooldown_event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_is_bot": { + "name": "target_is_bot", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "taxonomy_snapshot_id": { + "name": "taxonomy_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_aphia_id": { + "name": "species_aphia_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_accepted_name": { + "name": "species_accepted_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_display_name": { + "name": "species_display_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "species_family": { + "name": "species_family", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scene_id": { + "name": "scene_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "asset_url": { + "name": "asset_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "asset_checksum": { + "name": "asset_checksum", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "headline": { + "name": "headline", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "narrative": { + "name": "narrative", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metrics_json": { + "name": "metrics_json", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "accessibility_description": { + "name": "accessibility_description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "publication_status": { + "name": "publication_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "publication_failure": { + "name": "publication_failure", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "publication_failed_at": { + "name": "publication_failed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "message_bound_at": { + "name": "message_bound_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_status": { + "name": "response_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "response_type": { + "name": "response_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_actor_id": { + "name": "response_actor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "responded_at": { + "name": "responded_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "response_result_json": { + "name": "response_result_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_actor_id": { + "name": "counter_actor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_target_id": { + "name": "counter_target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_scene_id": { + "name": "counter_scene_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_asset_url": { + "name": "counter_asset_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_asset_checksum": { + "name": "counter_asset_checksum", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_headline": { + "name": "counter_headline", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_narrative": { + "name": "counter_narrative", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_metrics_json": { + "name": "counter_metrics_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_accessibility_description": { + "name": "counter_accessibility_description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "lobster_encounters_interaction_id_unique": { + "name": "lobster_encounters_interaction_id_unique", + "columns": [ + "interaction_id" + ], + "isUnique": true + }, + "lobster_encounters_cooldown_event_id_unique": { + "name": "lobster_encounters_cooldown_event_id_unique", + "columns": [ + "cooldown_event_id" + ], + "isUnique": true + }, + "idx_lobster_encounters_message": { + "name": "idx_lobster_encounters_message", + "columns": [ + "guild_id", + "channel_id", + "message_id" + ], + "isUnique": false + }, + "idx_lobster_encounters_species": { + "name": "idx_lobster_encounters_species", + "columns": [ + "species_aphia_id" + ], + "isUnique": false + }, + "idx_lobster_encounters_publication": { + "name": "idx_lobster_encounters_publication", + "columns": [ + "publication_status" + ], + "isUnique": false + }, + "idx_lobster_encounters_response": { + "name": "idx_lobster_encounters_response", + "columns": [ + "response_status" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "nomination_approvals": { + "name": "nomination_approvals", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "nomination_id": { + "name": "nomination_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "approver_id": { + "name": "approver_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "vote_choice": { + "name": "vote_choice", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'approve'" + }, + "mutation_id": { + "name": "mutation_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_nomination_approvals_nomination_approver": { + "name": "idx_nomination_approvals_nomination_approver", + "columns": [ + "nomination_id", + "approver_id" + ], + "isUnique": true + }, + "idx_nomination_approvals_nomination_id": { + "name": "idx_nomination_approvals_nomination_id", + "columns": [ + "nomination_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "nominations": { + "name": "nominations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nominee_id": { + "name": "nominee_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "nominator_id": { + "name": "nominator_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'No reason provided.'" + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "target_role_id": { + "name": "target_role_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "required_approvals": { + "name": "required_approvals", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'submitted'" + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "desired_card_revision": { + "name": "desired_card_revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "synced_card_revision": { + "name": "synced_card_revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "card_sync_started_at": { + "name": "card_sync_started_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "card_sync_failure_count": { + "name": "card_sync_failure_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "grant_started_at": { + "name": "grant_started_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "grant_failure_count": { + "name": "grant_failure_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_nominations_active_unique": { + "name": "idx_nominations_active_unique", + "columns": [ + "guild_id", + "nominee_id", + "target_role_id" + ], + "isUnique": true, + "where": "\"nominations\".\"status\" in ('submitted', 'granting')" + }, + "idx_nominations_status": { + "name": "idx_nominations_status", + "columns": [ + "status" + ], + "isUnique": false + }, + "idx_nominations_card_sync": { + "name": "idx_nominations_card_sync", + "columns": [ + "desired_card_revision", + "synced_card_revision" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "quilt_wal": { + "name": "quilt_wal", + "columns": { + "seq": { + "name": "seq", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "mutation_id": { + "name": "mutation_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ts": { + "name": "ts", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cell": { + "name": "cell", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "op": { + "name": "op", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prev_hash": { + "name": "prev_hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "quilt_wal_mutation_idx": { + "name": "quilt_wal_mutation_idx", + "columns": [ + "mutation_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "quilt_wal_lock": { + "name": "quilt_wal_lock", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "holder": { + "name": "holder", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "acquired_at": { + "name": "acquired_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "reddit_moderation_contexts": { + "name": "reddit_moderation_contexts", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "subreddit": { + "name": "subreddit", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'moderated'" + }, + "unaction": { + "name": "unaction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'reviewed'" + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "moderator": { + "name": "moderator", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "banned_at": { + "name": "banned_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "idx_reddit_moderation_contexts_subreddit_username": { + "name": "idx_reddit_moderation_contexts_subreddit_username", + "columns": [ + "subreddit", + "username" + ], + "isUnique": true + }, + "idx_reddit_moderation_contexts_username": { + "name": "idx_reddit_moderation_contexts_username", + "columns": [ + "username" + ], + "isUnique": false + }, + "idx_reddit_moderation_contexts_action": { + "name": "idx_reddit_moderation_contexts_action", + "columns": [ + "action" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "slap_events": { + "name": "slap_events", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "interaction_id": { + "name": "interaction_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_is_bot": { + "name": "target_is_bot", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "fish_slug": { + "name": "fish_slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fish_name": { + "name": "fish_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rarity": { + "name": "rarity", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "headline": { + "name": "headline", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "narrative": { + "name": "narrative", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impact": { + "name": "impact", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "dignity_remaining": { + "name": "dignity_remaining", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fish_condition": { + "name": "fish_condition", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "counter_actor_id": { + "name": "counter_actor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_target_id": { + "name": "counter_target_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_fish_slug": { + "name": "counter_fish_slug", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_fish_name": { + "name": "counter_fish_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_rarity": { + "name": "counter_rarity", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_outcome": { + "name": "counter_outcome", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_headline": { + "name": "counter_headline", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_narrative": { + "name": "counter_narrative", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_impact": { + "name": "counter_impact", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_dignity_remaining": { + "name": "counter_dignity_remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_fish_condition": { + "name": "counter_fish_condition", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "counter_image_url": { + "name": "counter_image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "countered_at": { + "name": "countered_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appealed_by_id": { + "name": "appealed_by_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appeal_ruling": { + "name": "appeal_ruling", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "appealed_at": { + "name": "appealed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "slap_events_interaction_id_unique": { + "name": "slap_events_interaction_id_unique", + "columns": [ + "interaction_id" + ], + "isUnique": true + }, + "idx_slap_events_actor_cooldown": { + "name": "idx_slap_events_actor_cooldown", + "columns": [ + "guild_id", + "actor_id", + "created_at" + ], + "isUnique": false + }, + "idx_slap_events_target_cooldown": { + "name": "idx_slap_events_target_cooldown", + "columns": [ + "guild_id", + "target_id", + "created_at" + ], + "isUnique": false + }, + "idx_slap_events_channel_cooldown": { + "name": "idx_slap_events_channel_cooldown", + "columns": [ + "guild_id", + "channel_id", + "created_at" + ], + "isUnique": false + }, + "idx_slap_events_message": { + "name": "idx_slap_events_message", + "columns": [ + "guild_id", + "channel_id", + "message_id" + ], + "isUnique": false + }, + "idx_slap_events_outcome": { + "name": "idx_slap_events_outcome", + "columns": [ + "outcome" + ], + "isUnique": false + }, + "idx_slap_events_rarity": { + "name": "idx_slap_events_rarity", + "columns": [ + "rarity" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tracked_threads": { + "name": "tracked_threads", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_checked": { + "name": "last_checked", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "solved": { + "name": "solved", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "warning_level": { + "name": "warning_level", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "closed": { + "name": "closed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_message_count": { + "name": "last_message_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "received_at": { + "name": "received_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "raw_payload": { + "name": "raw_payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "tracked_threads_thread_id_unique": { + "name": "tracked_threads_thread_id_unique", + "columns": [ + "thread_id" + ], + "isUnique": true + }, + "idx_tracked_threads_solved": { + "name": "idx_tracked_threads_solved", + "columns": [ + "solved" + ], + "isUnique": false + }, + "idx_tracked_threads_last_checked": { + "name": "idx_tracked_threads_last_checked", + "columns": [ + "last_checked" + ], + "isUnique": false + }, + "idx_tracked_threads_received_at": { + "name": "idx_tracked_threads_received_at", + "columns": [ + "received_at" + ], + "isUnique": false + }, + "idx_tracked_threads_closed": { + "name": "idx_tracked_threads_closed", + "columns": [ + "closed" + ], + "isUnique": false + }, + "idx_tracked_threads_warning_level": { + "name": "idx_tracked_threads_warning_level", + "columns": [ + "warning_level" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 3f7e3ae..165923f 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -99,6 +99,13 @@ "when": 1789635290938, "tag": "0013_quilt_kernel_wal", "breakpoints": true + }, + { + "idx": 14, + "version": "6", + "when": 1789640536915, + "tag": "0014_wandering_owl", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/db/schema.ts b/src/db/schema.ts index 20713f6..5fbf930 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -489,3 +489,14 @@ export const quiltWal = sqliteTable( (table) => [index("quilt_wal_mutation_idx").on(table.mutationId)] ) export type QuiltWalRow = typeof quiltWal.$inferSelect + +// Single-row claim lock serializing WAL commits across Worker isolates. +// Review finding #1: two interleaved commitProjection calls both read the +// same chain tip, then both insert — the hash chain self-invalidates +// permanently, silently. An in-memory mutex cannot hold across isolates; +// the lock lives in D1, claimed and released around each commit. +export const quiltWalLock = sqliteTable("quilt_wal_lock", { + id: integer().primaryKey(), + holder: text().notNull(), + acquiredAt: text("acquired_at").notNull() +}) diff --git a/src/quilt/commit.ts b/src/quilt/commit.ts index 311c1c9..0779b00 100644 --- a/src/quilt/commit.ts +++ b/src/quilt/commit.ts @@ -1,4 +1,14 @@ // commit.ts — dual-write state transitions into the quilt WAL. +// +// Review finding #1 (BLOCKER): the tip-read and the insert were separate +// D1 batches. Two interleaved writers both read the same tip, then both +// insert — the hash chain self-invalidates permanently, silently, and +// nothing throws. An in-memory mutex cannot hold across Cloudflare Worker +// isolates, so the commit serializer lives in D1: a single-row claim lock +// with a stale-holder TTL. Claim → read tip → insert → release, all under +// the lock. The lock is best-effort: on claim exhaustion the projection +// is SKIPPED (mirror posture — the user flow never breaks), which is now +// a loud, countable event rather than silent corruption. import { QuiltKernel, type QuiltEvent } from "./reference-kernel.mjs" import { buildWalRows, @@ -21,57 +31,127 @@ export type CommitContext = { ts: string } +const LOCK_TTL_MS = 30_000 +const LOCK_ATTEMPTS = 8 +const seed = Date.now().toString(36) +let nonce = 0 +const nextHolder = (mutationId: string) => + `${mutationId}:${seed}:${(nonce += 1)}` + +const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)) + +const claimWalLock = async ( + client: WalClient, + holder: string, + now: Date +): Promise => { + const nowIso = now.toISOString() + const staleBefore = new Date(now.getTime() - LOCK_TTL_MS).toISOString() + await client.batch([ + client.prepare( + `insert or ignore into quilt_wal_lock (id, holder, acquired_at) + values (1, '', '')` + ) + ]) + for (let attempt = 0; attempt < LOCK_ATTEMPTS; attempt++) { + const [claimed] = await client.batch<{ id: number }>([ + client + .prepare( + `update quilt_wal_lock + set holder = ?, acquired_at = ? + where id = 1 and (holder = '' or acquired_at < ?) + returning id` + ) + .bind(holder, nowIso, staleBefore) + ]) + if (claimed?.results?.[0]) return true + await sleep(Math.min(200, 5 * 2 ** attempt) + Math.floor(Math.random() * 10)) + } + return false +} + +const releaseWalLock = async ( + client: WalClient, + holder: string +): Promise => { + await client.batch([ + client + .prepare( + `update quilt_wal_lock + set holder = '', acquired_at = '' + where id = 1 and holder = ?` + ) + .bind(holder) + ]) +} + // Generic projector: run `project` against a fresh kernel, drain the -// events, append hash-chained WAL rows in ONE batch. Returns rows written. +// events, append hash-chained WAL rows serialized by the D1 claim lock. +// Returns rows written (0 when lock acquisition fails or no events). export const commitProjection = async ( client: WalClient, context: CommitContext, project: (kernel: QuiltKernel) => void ): Promise => { - const kernel = new QuiltKernel() - const events: QuiltEvent[] = [] - const unsubscribe = kernel.subscribe((event) => { - events.push(event) - }) - project(kernel) - unsubscribe() - - const [tipResult] = await client.batch([ - client.prepare( - `select coalesce(max(seq), 0) as tip, - (select hash from quilt_wal order by seq desc limit 1) as prev - from quilt_wal` + const holder = nextHolder(context.mutationId) + const acquired = await claimWalLock(client, holder, new Date()) + if (!acquired) { + console.warn( + "quilt wal lock not acquired; projection skipped", + context.mutationId ) - ]) - const tipRow = tipResult?.results?.[0] ?? { tip: 0, prev: null } - const rows = buildWalRows(events, { - mutationId: context.mutationId, - ts: context.ts, - tip: Number(tipRow.tip ?? 0), - prevHash: tipRow.prev ?? null - }) - if (rows.length === 0) return 0 + return 0 + } + try { + const kernel = new QuiltKernel() + const events: QuiltEvent[] = [] + const unsubscribe = kernel.subscribe((event) => { + events.push(event) + }) + project(kernel) + unsubscribe() + if (events.length === 0) return 0 - await client.batch( - rows.map((row: WalRow) => - client - .prepare( - `insert into quilt_wal - (mutation_id, ts, cell, op, value, prev_hash, hash) - values (?, ?, ?, ?, ?, ?, ?)` - ) - .bind( - row.mutation_id, - row.ts, - row.cell, - row.op, - row.value, - row.prev_hash, - row.hash - ) + const [tipResult] = await client.batch([ + client.prepare( + `select coalesce(max(seq), 0) as tip, + (select hash from quilt_wal order by seq desc limit 1) as prev + from quilt_wal` + ) + ]) + const tipRow = tipResult?.results?.[0] ?? { tip: 0, prev: null } + const rows = buildWalRows(events, { + mutationId: context.mutationId, + ts: context.ts, + tip: Number(tipRow.tip ?? 0), + prevHash: tipRow.prev ?? null + }) + if (rows.length === 0) return 0 + + await client.batch( + rows.map((row: WalRow) => + client + .prepare( + `insert into quilt_wal + (mutation_id, ts, cell, op, value, prev_hash, hash) + values (?, ?, ?, ?, ?, ?, ?)` + ) + .bind( + row.mutation_id, + row.ts, + row.cell, + row.op, + row.value, + row.prev_hash, + row.hash + ) + ) ) - ) - return rows.length + return rows.length + } finally { + await releaseWalLock(client, holder).catch(() => {}) + } } // P1 entry point — kept for src/data/nominations.ts. diff --git a/src/quilt/projection.ts b/src/quilt/projection.ts index f750257..13fbbfb 100644 --- a/src/quilt/projection.ts +++ b/src/quilt/projection.ts @@ -35,50 +35,19 @@ export type WalRow = { hash: string } -export type VoteProjectionInput = { - nominationId: number - reviewerId: string - choice: "approve" | "decline" - resultKind: - | "recorded" - | "switched" - | "granting" - | "declined" - | "expired" - status: string - totals: { approvals: number; declines: number } - completedAt: string | null - mutationId: string - ts: string -} - export type KernelLike = { bind(name: string, value?: unknown, meta?: unknown): unknown link(from: string, to: string, type: string): string unsubscribe?: () => void } -// Mirror one recordNominationVote transition into kernel ops. Every write -// is a BIND; the voter's cell LINKs to the nomination cell ('cast'). -export const projectNominationVote = ( - kernel: KernelLike, - input: VoteProjectionInput -): void => { - const base = `nomination.${input.nominationId}` - // the nomination itself is a cell — link endpoints must exist (L1 law) - kernel.bind(base, { id: input.nominationId, kind: "nomination" }) - kernel.bind(`${base}.mutation`, input.mutationId, { ts: input.ts }) - kernel.bind(`${base}.status`, input.status) - kernel.bind(`${base}.totals`, input.totals) - kernel.bind(`${base}.completedAt`, input.completedAt) - if (input.resultKind !== "expired") { - const voteCell = `${base}.vote.${input.reviewerId}` - kernel.bind(voteCell, input.choice, { ts: input.ts }) - kernel.link(voteCell, base, "cast") - } -} - -// Turn drained kernel events into hash-chained WAL rows, continuing the +// THREAT MODEL (review finding #8): the chain is FNV-1a, unkeyed, 32-bit. +// It proves CONTINUITY (no row altered, none missing, in sequence order), +// not tamper-evidence against a writer with table access — anyone who can +// update quilt_wal can recompute a valid suffix. Upgrade path: swap fnv1a +// for sha256 over the same input string; verifyChain's row format is +// hash-function-agnostic. Do not cite the WAL in audit context until the +// sha256 upgrade lands.// Turn drained kernel events into hash-chained WAL rows, continuing the // chain from `tip` (0 for genesis) and `prevHash`. export const buildWalRows = ( events: Array<{ kind: string; cell: string | null; value: unknown }>, @@ -162,9 +131,20 @@ export const replayNominationFromWal = ( nominationId: number ): ReplayedNomination | null => { const prefix = `nomination.${nominationId}.` + const base = `nomination.${nominationId}` const cells = new Map() - for (const row of rows) { - if (row.op !== "bind" || !row.cell.startsWith(prefix)) continue + // findings #3/#7: never trust caller row order; honor unbinds. copy + + // sort so `seq desc` input replays identically to `seq asc`. + const ordered = [...rows].sort((a, b) => a.seq - b.seq) + for (const row of ordered) { + // the bare entity bind IS the entity marker; sub-cells carry + // the properties. both belong in the map. + if (row.cell !== base && !row.cell.startsWith(prefix)) continue + if (row.op === "unbind") { + cells.delete(row.cell) + continue + } + if (row.op !== "bind") continue cells.set(row.cell, row.value === null ? null : JSON.parse(row.value)) } if (cells.size === 0) return null @@ -324,37 +304,54 @@ export const analyzeRefusals = ( rows: WalRow[], guildId?: string ): RefusalRecord[] => { - const records: RefusalRecord[] = [] + // finding #4: suffix-strip the interactionId (cell shape is exactly + // `encounter..refused`, and may itself contain dots), index + // attempts in one pass instead of O(n²) finds, and never let one bad + // row kill the whole analysis. + const ATTEMPT_PREFIX = "encounter." + const REFUSED_SUFFIX = ".refused" + const parse = (raw: string | null | undefined): Record => { + if (!raw) return {} + try { + return JSON.parse(raw) as Record + } catch { + return {} + } + } + const attempts = new Map>() for (const row of rows) { - if (row.op !== "bind" || !row.cell.endsWith(".refused")) continue - const payload = JSON.parse(row.value ?? "{}") as { - refusedBy?: string[] - remaining?: Array<{ kind: string; remainingSeconds: number }> - ts?: string + if (row.op !== "bind") continue + // index EVERY bind cell by exact key — the attempt cell for a + // refusal is `encounter.` constructed exactly, so dotted + // interaction ids can never collide with sub-cells. + if (!attempts.has(row.cell)) { + attempts.set(row.cell, parse(row.value)) } - const parts = row.cell.split(".") - const interactionId = parts[1] - const attemptRow = rows.find( - (candidate) => - candidate.op === "bind" && - candidate.cell === `encounter.${interactionId}` && - candidate.seq < row.seq + } + + const records: RefusalRecord[] = [] + for (const row of rows) { + if (row.op !== "bind" || !row.cell.endsWith(REFUSED_SUFFIX)) continue + const interactionId = row.cell.slice( + ATTEMPT_PREFIX.length, + row.cell.length - REFUSED_SUFFIX.length ) - const attempt = JSON.parse(attemptRow?.value ?? "{}") as { - guildId?: string - channelId?: string - actorId?: string - targetId?: string - } + const payload = parse(row.value) + const attempt = attempts.get(`${ATTEMPT_PREFIX}${interactionId}`) ?? {} if (guildId && attempt.guildId !== guildId) continue records.push({ interactionId, - actorId: attempt.actorId ?? "", - targetId: attempt.targetId ?? "", - channelId: attempt.channelId ?? "", - refusedBy: payload.refusedBy ?? [], - remaining: payload.remaining ?? [], - ts: payload.ts ?? row.ts + actorId: typeof attempt.actorId === "string" ? attempt.actorId : "", + targetId: typeof attempt.targetId === "string" ? attempt.targetId : "", + channelId: + typeof attempt.channelId === "string" ? attempt.channelId : "", + refusedBy: Array.isArray(payload.refusedBy) + ? (payload.refusedBy as string[]) + : [], + remaining: Array.isArray(payload.remaining) + ? (payload.remaining as RefusalRecord["remaining"]) + : [], + ts: typeof payload.ts === "string" ? payload.ts : row.ts }) } return records @@ -378,9 +375,18 @@ export const replayEncounterFromWal = ( encounterId: number ): ReplayedEncounter | null => { const prefix = `encounter.${encounterId}.` + const base = `encounter.${encounterId}` const cells = new Map() - for (const row of rows) { - if (row.op !== "bind" || !row.cell.startsWith(prefix)) continue + // findings #3/#7: sort by seq internally; unbind deletes the cell; the + // bare entity bind is the entity marker and counts. + const ordered = [...rows].sort((a, b) => a.seq - b.seq) + for (const row of ordered) { + if (row.cell !== base && !row.cell.startsWith(prefix)) continue + if (row.op === "unbind") { + cells.delete(row.cell) + continue + } + if (row.op !== "bind") continue cells.set(row.cell, row.value === null ? null : JSON.parse(row.value)) } if (cells.size === 0) return null diff --git a/tests/quiltKernelEncounters.test.ts b/tests/quiltKernelEncounters.test.ts index 1402234..05875c5 100644 --- a/tests/quiltKernelEncounters.test.ts +++ b/tests/quiltKernelEncounters.test.ts @@ -27,7 +27,7 @@ import { SqliteD1Database } from "./helpers/sqliteD1.js" // and never see 0013 — unchanged suites stay honest. const migrationPaths = readdirSync("drizzle") .filter((file) => - /0002_.*\.sql|000[4-9]_.*\.sql|001[013]_.*\.sql/.test(file) + /0002_.*\.sql|000[4-9]_.*\.sql|001[0134]_.*\.sql/.test(file) ) .sort() diff --git a/tests/quiltKernelReconcile.test.ts b/tests/quiltKernelReconcile.test.ts index a1342c0..c25c65e 100644 --- a/tests/quiltKernelReconcile.test.ts +++ b/tests/quiltKernelReconcile.test.ts @@ -23,7 +23,7 @@ import { SqliteD1Database } from "./helpers/sqliteD1.js" const migrationPaths = readdirSync("drizzle") .filter((file) => - /0002_.*\.sql|000[4-9]_.*\.sql|001[013]_.*\.sql/.test(file) + /0002_.*\.sql|000[4-9]_.*\.sql|001[0134]_.*\.sql/.test(file) ) .sort() diff --git a/tests/quiltKernelReplay.test.ts b/tests/quiltKernelReplay.test.ts index 9d48d58..53cc645 100644 --- a/tests/quiltKernelReplay.test.ts +++ b/tests/quiltKernelReplay.test.ts @@ -22,7 +22,7 @@ import { SqliteD1Database } from "./helpers/sqliteD1.js" // Existing suites filter 000[4-9] and never see 0013 — unchanged suites // stay honest. const migrationPaths = readdirSync("drizzle") - .filter((file) => /0002_.*\.sql|000[4-9]_.*\.sql|0013_.*\.sql/.test(file)) + .filter((file) => /0002_.*\.sql|000[4-9]_.*\.sql|001[34]_.*\.sql/.test(file)) .sort() const applyMigrations = (database: Database) => { diff --git a/tests/quiltKernelReviewFixes.test.ts b/tests/quiltKernelReviewFixes.test.ts new file mode 100644 index 0000000..7e95646 --- /dev/null +++ b/tests/quiltKernelReviewFixes.test.ts @@ -0,0 +1,232 @@ +// quiltKernelReviewFixes.test.ts — regression tests for the adversarial +// review findings. Finding #1's probe (two interleaved commits) lived in +// the reviewer's hands, not in the suite; it lives here now. +import { Database } from "bun:sqlite" +import { describe, expect, it } from "bun:test" +import { readdirSync, readFileSync } from "node:fs" +import { drizzle } from "drizzle-orm/d1" +import * as schema from "../src/db/schema.js" +import { commitProjection } from "../src/quilt/commit.js" +import { + analyzeRefusals, + replayEncounterFromWal, + verifyChain, + type WalRow +} from "../src/quilt/projection.js" +import { SqliteD1Database } from "./helpers/sqliteD1.js" + +const migrationPaths = readdirSync("drizzle") + .filter((file) => + /0002_.*\.sql|000[4-9]_.*\.sql|001[0134]_.*\.sql/.test(file) + ) + .sort() + +const applyMigrations = (database: Database) => { + for (const path of migrationPaths) { + const migration = readFileSync(`drizzle/${path}`, "utf8") + for (const statement of migration.split("--> statement-breakpoint")) { + const trimmed = statement.trim() + if (trimmed) { + database.run(trimmed) + } + } + } +} + +const createHarness = () => { + const owner = new SqliteD1Database() + applyMigrations(owner.database) + return { owner } +} + +const readWalRows = async (owner: SqliteD1Database): Promise => { + const result = await owner + .prepare( + `select seq, mutation_id, ts, cell, op, value, prev_hash, hash + from quilt_wal order by seq asc` + ) + .all() + return (result.results ?? []).map((row) => ({ + seq: Number(row.seq), + mutation_id: row.mutation_id, + ts: row.ts, + cell: row.cell, + op: row.op, + value: row.value, + prev_hash: row.prev_hash, + hash: row.hash + })) +} + +describe("quilt kernel — review fixes", () => { + it("finding #1: interleaved commits keep a valid chain (the probe)", async () => { + const { owner } = createHarness() + const client = owner as unknown as Parameters< + typeof commitProjection + >[0] + const ts = "2026-09-17T00:00:00.000Z" + + // fire both WITHOUT awaiting the first — the interleaving that + // broke the chain before the claim lock existed + const first = commitProjection( + client, + { mutationId: "m-A", ts }, + (kernel) => { + kernel.bind("nomination.1", { id: 1, kind: "nomination" }) + kernel.bind("nomination.1.status", "submitted") + } + ) + const second = commitProjection( + client, + { mutationId: "m-B", ts }, + (kernel) => { + kernel.bind("nomination.2", { id: 2, kind: "nomination" }) + kernel.bind("nomination.2.status", "submitted") + } + ) + const [rowsA, rowsB] = await Promise.all([first, second]) + expect(rowsA + rowsB).toBe(4) + + const rows = await readWalRows(owner) + const verification = verifyChain(rows) + expect(verification.ok).toBe(true) + const lock = await owner + .prepare(`select holder from quilt_wal_lock where id = 1`) + .all<{ holder: string }>() + expect(lock.results?.[0]?.holder).toBe("") + owner.close() + }) + + it("finding #3: replay is order-independent in the caller", async () => { + const { owner } = createHarness() + const client = owner as unknown as Parameters< + typeof commitProjection + >[0] + const ts = "2026-09-17T00:00:00.000Z" + await commitProjection(client, { mutationId: "m-1", ts }, (kernel) => { + kernel.bind("encounter.7", { id: 7, kind: "lobster-encounter" }) + kernel.bind("encounter.7.publication", "pending") + kernel.bind("encounter.7.publication", "published") + }) + const rows = await readWalRows(owner) + const forward = replayEncounterFromWal(rows, 7) + const backward = replayEncounterFromWal([...rows].reverse(), 7) + expect(forward?.publication).toBe("published") + expect(backward?.publication).toBe("published") + owner.close() + }) + + it("finding #7: unbind removes the cell from replay", async () => { + const { owner } = createHarness() + const client = owner as unknown as Parameters< + typeof commitProjection + >[0] + const ts = "2026-09-17T00:00:00.000Z" + await commitProjection(client, { mutationId: "m-1", ts }, (kernel) => { + kernel.bind("encounter.9", { id: 9, kind: "lobster-encounter" }) + kernel.bind("encounter.9.message", "msg-1") + kernel.unbind("encounter.9.message") + }) + const rows = await readWalRows(owner) + const replayed = replayEncounterFromWal(rows, 9) + expect(replayed).not.toBeNull() + expect(replayed?.message).toBeNull() + owner.close() + }) + + it("finding #4: analyzeRefusals survives corrupt rows and dotted ids", async () => { + const { owner } = createHarness() + const client = owner as unknown as Parameters< + typeof commitProjection + >[0] + const ts = "2026-09-17T00:00:00.000Z" + await commitProjection( + client, + { mutationId: "m-dotted", ts }, + (kernel) => { + kernel.bind("encounter.ix.with.dots", { + kind: "lobster-encounter-attempt", + guildId: "g-1", + actorId: "a-1", + targetId: "t-1", + channelId: "c-1" + }) + kernel.bind("encounter.ix.with.dots.refused", { + refusedBy: ["actor"], + remaining: [{ kind: "actor", remainingSeconds: 12 }], + ts + }) + } + ) + // one deliberately corrupt payload row + owner.database + .query( + `insert into quilt_wal + (mutation_id, ts, cell, op, value, prev_hash, hash) + values ('m-corrupt', ?, 'encounter.bogus.refused', 'bind', + '{not json', 'x', 'y')` + ) + .run(ts) + + const rows = await readWalRows(owner) + expect(() => analyzeRefusals(rows)).not.toThrow() + const records = analyzeRefusals(rows, "g-1") + expect(records).toHaveLength(1) + expect(records[0]?.interactionId).toBe("ix.with.dots") + expect(records[0]?.refusedBy).toEqual(["actor"]) + owner.close() + }) + + it("lock posture: unbreakable lock skips the projection, never corrupts", async () => { + const { owner } = createHarness() + const client = owner as unknown as Parameters< + typeof commitProjection + >[0] + const ts = "2026-09-17T00:00:00.000Z" + // a live holder with a FRESH timestamp: every claim attempt bounces + owner.database + .query( + `insert into quilt_wal_lock (id, holder, acquired_at) + values (1, 'stuck-holder', ?)` + ) + .run(new Date().toISOString()) + + const written = await commitProjection( + client, + { mutationId: "m-skipped", ts }, + (kernel) => { + kernel.bind("nomination.3", { id: 3, kind: "nomination" }) + } + ) + expect(written).toBe(0) + const rows = await readWalRows(owner) + expect(rows).toHaveLength(0) + owner.close() + }) + + it("lock posture: a stale holder is broken and the commit proceeds", async () => { + const { owner } = createHarness() + const client = owner as unknown as Parameters< + typeof commitProjection + >[0] + const ts = "2026-09-17T00:00:00.000Z" + owner.database + .query( + `insert into quilt_wal_lock (id, holder, acquired_at) + values (1, 'dead-holder', ?)` + ) + .run(new Date(Date.now() - 60_000).toISOString()) + + const written = await commitProjection( + client, + { mutationId: "m-stale", ts }, + (kernel) => { + kernel.bind("nomination.4", { id: 4, kind: "nomination" }) + } + ) + expect(written).toBe(1) + const rows = await readWalRows(owner) + expect(verifyChain(rows).ok).toBe(true) + owner.close() + }) +})