366 lines
12 KiB
SQL
366 lines
12 KiB
SQL
-- +goose Up
|
|||
|
|
ALTER TABLE execution_result_requests RENAME TO execution_result_requests_v5;
|
||
|
|
|
||
|
|
CREATE TABLE execution_result_requests (
|
||
|
|
user_id TEXT NOT NULL
|
||
|
|
REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
device_id TEXT NOT NULL
|
||
|
|
REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
operation TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
operation IN (
|
||
|
|
'EVENTS',
|
||
|
|
'EVIDENCE',
|
||
|
|
'CANDIDATES',
|
||
|
|
'HUMAN_REVIEW',
|
||
|
|
'COMPLETE',
|
||
|
|
'FAIL'
|
||
|
|
)
|
||
|
|
),
|
||
|
|
idempotency_key TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(idempotency_key)) > 0
|
||
|
|
AND length(CAST(idempotency_key AS BLOB)) <= 128
|
||
|
|
),
|
||
|
|
request_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(request_sha256) = 64
|
||
|
|
AND request_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
claim_token_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(claim_token_sha256) = 64
|
||
|
|
AND claim_token_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
task_id TEXT NOT NULL
|
||
|
|
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
execution_id TEXT NOT NULL
|
||
|
|
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
resource_id TEXT,
|
||
|
|
created_at TEXT NOT NULL,
|
||
|
|
PRIMARY KEY (user_id, device_id, operation, idempotency_key)
|
||
|
|
);
|
||
|
|
|
||
|
|
INSERT INTO execution_result_requests (
|
||
|
|
user_id,
|
||
|
|
device_id,
|
||
|
|
operation,
|
||
|
|
idempotency_key,
|
||
|
|
request_sha256,
|
||
|
|
claim_token_sha256,
|
||
|
|
task_id,
|
||
|
|
execution_id,
|
||
|
|
resource_id,
|
||
|
|
created_at
|
||
|
|
)
|
||
|
|
SELECT
|
||
|
|
user_id,
|
||
|
|
device_id,
|
||
|
|
operation,
|
||
|
|
idempotency_key,
|
||
|
|
request_sha256,
|
||
|
|
claim_token_sha256,
|
||
|
|
task_id,
|
||
|
|
execution_id,
|
||
|
|
resource_id,
|
||
|
|
created_at
|
||
|
|
FROM execution_result_requests_v5;
|
||
|
|
|
||
|
|
DROP TABLE execution_result_requests_v5;
|
||
|
|
|
||
|
|
CREATE TABLE candidate_search_runs (
|
||
|
|
execution_id TEXT PRIMARY KEY NOT NULL
|
||
|
|
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
task_id TEXT NOT NULL
|
||
|
|
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
task_content_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(task_content_sha256) = 64
|
||
|
|
AND task_content_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
execution_mode TEXT NOT NULL
|
||
|
|
CHECK (execution_mode IN ('MANUAL_FIRST', 'AI_ASSISTED')),
|
||
|
|
search_query TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(search_query)) > 0
|
||
|
|
AND length(CAST(search_query AS BLOB)) <= 512
|
||
|
|
),
|
||
|
|
app_version TEXT,
|
||
|
|
android_version TEXT,
|
||
|
|
pdd_version TEXT,
|
||
|
|
started_at TEXT NOT NULL,
|
||
|
|
received_at TEXT NOT NULL,
|
||
|
|
observation_count INTEGER NOT NULL
|
||
|
|
CHECK (observation_count BETWEEN 0 AND 5),
|
||
|
|
collection_complete INTEGER NOT NULL
|
||
|
|
CHECK (collection_complete = 1),
|
||
|
|
received_after_execution_expiry INTEGER NOT NULL DEFAULT 0
|
||
|
|
CHECK (received_after_execution_expiry IN (0, 1))
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE candidate_observations (
|
||
|
|
execution_id TEXT NOT NULL
|
||
|
|
REFERENCES candidate_search_runs(execution_id)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
task_id TEXT NOT NULL
|
||
|
|
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
ordinal INTEGER NOT NULL
|
||
|
|
CHECK (ordinal BETWEEN 1 AND 5),
|
||
|
|
title TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(title)) > 0
|
||
|
|
AND length(CAST(title AS BLOB)) <= 512
|
||
|
|
),
|
||
|
|
sku_text TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(sku_text AS BLOB)) <= 512),
|
||
|
|
price_text TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(price_text AS BLOB)) <= 64),
|
||
|
|
product_url TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(product_url AS BLOB)) <= 2048),
|
||
|
|
image_url TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(image_url AS BLOB)) <= 2048),
|
||
|
|
evidence_asset_ids_json TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(evidence_asset_ids_json AS BLOB)) <= 4096),
|
||
|
|
collection_status TEXT NOT NULL
|
||
|
|
CHECK (collection_status IN ('COMPLETE', 'PARTIAL')),
|
||
|
|
observed_at TEXT NOT NULL,
|
||
|
|
PRIMARY KEY (execution_id, ordinal)
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE model_runs (
|
||
|
|
execution_id TEXT PRIMARY KEY NOT NULL
|
||
|
|
REFERENCES candidate_search_runs(execution_id)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
provider_id TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(provider_id)) > 0
|
||
|
|
AND length(CAST(provider_id AS BLOB)) <= 128
|
||
|
|
),
|
||
|
|
model TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(model)) > 0
|
||
|
|
AND length(CAST(model AS BLOB)) <= 256
|
||
|
|
),
|
||
|
|
prompt_version TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(prompt_version)) > 0
|
||
|
|
AND length(CAST(prompt_version AS BLOB)) <= 128
|
||
|
|
),
|
||
|
|
schema_version INTEGER NOT NULL
|
||
|
|
CHECK (schema_version BETWEEN 1 AND 1000),
|
||
|
|
recommendation_threshold REAL NOT NULL
|
||
|
|
CHECK (recommendation_threshold BETWEEN 0 AND 1),
|
||
|
|
request_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(request_sha256) = 64
|
||
|
|
AND request_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
result_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(result_sha256) = 64
|
||
|
|
AND result_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
duration_millis INTEGER,
|
||
|
|
input_tokens INTEGER,
|
||
|
|
output_tokens INTEGER,
|
||
|
|
cost_microunits INTEGER,
|
||
|
|
created_at TEXT NOT NULL
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE candidate_evaluations (
|
||
|
|
execution_id TEXT NOT NULL,
|
||
|
|
candidate_ordinal INTEGER NOT NULL,
|
||
|
|
decision TEXT NOT NULL
|
||
|
|
CHECK (decision IN ('REVIEW', 'REJECT', 'MANUAL_REQUIRED')),
|
||
|
|
score REAL NOT NULL
|
||
|
|
CHECK (score BETWEEN 0 AND 1),
|
||
|
|
confidence REAL NOT NULL
|
||
|
|
CHECK (confidence BETWEEN 0 AND 1),
|
||
|
|
matched_json TEXT NOT NULL,
|
||
|
|
missing_or_uncertain_json TEXT NOT NULL,
|
||
|
|
rejection_reasons_json TEXT NOT NULL,
|
||
|
|
hard_constraints_json TEXT NOT NULL,
|
||
|
|
created_at TEXT NOT NULL,
|
||
|
|
PRIMARY KEY (execution_id, candidate_ordinal),
|
||
|
|
FOREIGN KEY (execution_id)
|
||
|
|
REFERENCES model_runs(execution_id)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
FOREIGN KEY (execution_id, candidate_ordinal)
|
||
|
|
REFERENCES candidate_observations(execution_id, ordinal)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE candidate_recommendations (
|
||
|
|
execution_id TEXT PRIMARY KEY NOT NULL,
|
||
|
|
candidate_ordinal INTEGER NOT NULL,
|
||
|
|
conclusion TEXT NOT NULL
|
||
|
|
CHECK (conclusion = 'SUGGESTED'),
|
||
|
|
policy_version TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(policy_version)) > 0
|
||
|
|
AND length(CAST(policy_version AS BLOB)) <= 128
|
||
|
|
),
|
||
|
|
reasons_json TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(reasons_json AS BLOB)) <= 4096),
|
||
|
|
created_at TEXT NOT NULL,
|
||
|
|
FOREIGN KEY (execution_id, candidate_ordinal)
|
||
|
|
REFERENCES candidate_observations(execution_id, ordinal)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE candidate_human_reviews (
|
||
|
|
id TEXT PRIMARY KEY NOT NULL
|
||
|
|
CHECK (length(id) = 36),
|
||
|
|
execution_id TEXT NOT NULL
|
||
|
|
REFERENCES candidate_search_runs(execution_id)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
task_id TEXT NOT NULL
|
||
|
|
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
version INTEGER NOT NULL
|
||
|
|
CHECK (version > 0),
|
||
|
|
reason_schema_version INTEGER NOT NULL
|
||
|
|
CHECK (reason_schema_version = 1),
|
||
|
|
outcome TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
outcome IN (
|
||
|
|
'CANDIDATE_ACCEPTED',
|
||
|
|
'CANDIDATE_REJECTED',
|
||
|
|
'NO_MATCH',
|
||
|
|
'MANUAL_REQUIRED'
|
||
|
|
)
|
||
|
|
),
|
||
|
|
selected_candidate_ordinal INTEGER,
|
||
|
|
primary_reason_code TEXT NOT NULL,
|
||
|
|
note TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(note AS BLOB)) <= 800),
|
||
|
|
supersedes_review_id TEXT UNIQUE
|
||
|
|
REFERENCES candidate_human_reviews(id)
|
||
|
|
ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
actor_user_id TEXT NOT NULL
|
||
|
|
REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
actor_device_id TEXT
|
||
|
|
REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
created_at TEXT NOT NULL,
|
||
|
|
received_after_execution_expiry INTEGER NOT NULL DEFAULT 0
|
||
|
|
CHECK (received_after_execution_expiry IN (0, 1)),
|
||
|
|
UNIQUE (execution_id, version),
|
||
|
|
FOREIGN KEY (execution_id, selected_candidate_ordinal)
|
||
|
|
REFERENCES candidate_observations(execution_id, ordinal)
|
||
|
|
ON UPDATE RESTRICT ON DELETE RESTRICT
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE INDEX candidate_human_reviews_execution_version_idx
|
||
|
|
ON candidate_human_reviews (execution_id, version DESC);
|
||
|
|
|
||
|
|
CREATE TABLE candidate_human_review_items (
|
||
|
|
review_id TEXT NOT NULL
|
||
|
|
REFERENCES candidate_human_reviews(id)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE,
|
||
|
|
candidate_ordinal INTEGER NOT NULL,
|
||
|
|
label TEXT NOT NULL
|
||
|
|
CHECK (label IN ('ACCEPT', 'REJECT')),
|
||
|
|
primary_reason_code TEXT NOT NULL,
|
||
|
|
note TEXT NOT NULL
|
||
|
|
CHECK (length(CAST(note AS BLOB)) <= 800),
|
||
|
|
PRIMARY KEY (review_id, candidate_ordinal)
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE TABLE candidate_human_review_reasons (
|
||
|
|
review_id TEXT NOT NULL,
|
||
|
|
candidate_ordinal INTEGER NOT NULL,
|
||
|
|
reason_code TEXT NOT NULL,
|
||
|
|
PRIMARY KEY (review_id, candidate_ordinal, reason_code),
|
||
|
|
FOREIGN KEY (review_id, candidate_ordinal)
|
||
|
|
REFERENCES candidate_human_review_items(review_id, candidate_ordinal)
|
||
|
|
ON UPDATE RESTRICT ON DELETE CASCADE
|
||
|
|
);
|
||
|
|
|
||
|
|
-- +goose Down
|
||
|
|
CREATE TEMP TABLE candidate_decisions_v6_down_guard (
|
||
|
|
allowed INTEGER NOT NULL
|
||
|
|
CHECK (allowed = 1)
|
||
|
|
);
|
||
|
|
|
||
|
|
INSERT INTO candidate_decisions_v6_down_guard (allowed)
|
||
|
|
SELECT CASE
|
||
|
|
WHEN EXISTS (SELECT 1 FROM candidate_search_runs)
|
||
|
|
OR EXISTS (SELECT 1 FROM candidate_human_reviews)
|
||
|
|
OR EXISTS (
|
||
|
|
SELECT 1 FROM execution_result_requests
|
||
|
|
WHERE operation = 'HUMAN_REVIEW'
|
||
|
|
)
|
||
|
|
THEN 0
|
||
|
|
ELSE 1
|
||
|
|
END;
|
||
|
|
|
||
|
|
DROP TABLE candidate_decisions_v6_down_guard;
|
||
|
|
DROP TABLE candidate_human_review_reasons;
|
||
|
|
DROP TABLE candidate_human_review_items;
|
||
|
|
DROP INDEX candidate_human_reviews_execution_version_idx;
|
||
|
|
DROP TABLE candidate_human_reviews;
|
||
|
|
DROP TABLE candidate_recommendations;
|
||
|
|
DROP TABLE candidate_evaluations;
|
||
|
|
DROP TABLE model_runs;
|
||
|
|
DROP TABLE candidate_observations;
|
||
|
|
DROP TABLE candidate_search_runs;
|
||
|
|
|
||
|
|
ALTER TABLE execution_result_requests RENAME TO execution_result_requests_v6;
|
||
|
|
|
||
|
|
CREATE TABLE execution_result_requests (
|
||
|
|
user_id TEXT NOT NULL
|
||
|
|
REFERENCES users(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
device_id TEXT NOT NULL
|
||
|
|
REFERENCES devices(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
operation TEXT NOT NULL
|
||
|
|
CHECK (operation IN ('EVENTS', 'EVIDENCE', 'CANDIDATES', 'COMPLETE', 'FAIL')),
|
||
|
|
idempotency_key TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(trim(idempotency_key)) > 0
|
||
|
|
AND length(CAST(idempotency_key AS BLOB)) <= 128
|
||
|
|
),
|
||
|
|
request_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(request_sha256) = 64
|
||
|
|
AND request_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
claim_token_sha256 TEXT NOT NULL
|
||
|
|
CHECK (
|
||
|
|
length(claim_token_sha256) = 64
|
||
|
|
AND claim_token_sha256 NOT GLOB '*[^0-9a-f]*'
|
||
|
|
),
|
||
|
|
task_id TEXT NOT NULL
|
||
|
|
REFERENCES purchase_tasks(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
execution_id TEXT NOT NULL
|
||
|
|
REFERENCES task_executions(id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||
|
|
resource_id TEXT,
|
||
|
|
created_at TEXT NOT NULL,
|
||
|
|
PRIMARY KEY (user_id, device_id, operation, idempotency_key)
|
||
|
|
);
|
||
|
|
|
||
|
|
INSERT INTO execution_result_requests (
|
||
|
|
user_id,
|
||
|
|
device_id,
|
||
|
|
operation,
|
||
|
|
idempotency_key,
|
||
|
|
request_sha256,
|
||
|
|
claim_token_sha256,
|
||
|
|
task_id,
|
||
|
|
execution_id,
|
||
|
|
resource_id,
|
||
|
|
created_at
|
||
|
|
)
|
||
|
|
SELECT
|
||
|
|
user_id,
|
||
|
|
device_id,
|
||
|
|
operation,
|
||
|
|
idempotency_key,
|
||
|
|
request_sha256,
|
||
|
|
claim_token_sha256,
|
||
|
|
task_id,
|
||
|
|
execution_id,
|
||
|
|
resource_id,
|
||
|
|
created_at
|
||
|
|
FROM execution_result_requests_v6;
|
||
|
|
|
||
|
|
DROP TABLE execution_result_requests_v6;
|