Initial commit: Add project files
ci / backend (push) Failing after 12s
ci / frontend (push) Failing after 19s
ci / static (push) Failing after 45s

This commit is contained in:
2026-08-02 05:15:36 +09:00
commit dcd1322d41
636 changed files with 122352 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
create schema if not exists building_blocks;
create schema if not exists signal_engine;
create table if not exists building_blocks.outbox_message (
message_id uuid primary key,
event_type text not null,
schema_version integer not null check (schema_version > 0),
payload_json jsonb not null,
correlation_id text not null,
occurred_at timestamptz not null,
payload_hash text not null,
published_at timestamptz null,
attempt integer not null default 0
);
create table if not exists building_blocks.inbox_message (
consumer text not null,
message_id uuid not null,
received_at timestamptz not null,
payload_hash text not null,
primary key (consumer, message_id)
);
create table if not exists building_blocks.job_run (
job_run_id uuid primary key,
job_type text not null,
job_version integer not null,
scope_key text not null,
idempotency_key text not null unique,
watermark text null,
app_version text not null,
model_version text null,
config_version text null,
data_version text null,
contract_version text null,
status text not null,
input_hash text null,
output_hash text null,
started_at timestamptz null,
heartbeat_at timestamptz null,
finished_at timestamptz null,
error_code text null,
trace_id text null
);
+60
View File
@@ -0,0 +1,60 @@
create table if not exists signal_engine.evidence_snapshot (
evidence_id text primary key,
as_of timestamptz not null,
published_at_cutoff timestamptz not null,
dataset_id text not null,
data_hash text not null,
model_version text not null,
config_version text not null,
payload jsonb not null,
content_hash text not null unique,
created_at timestamptz not null default now()
);
create table if not exists signal_engine.signal_decision (
decision_id uuid primary key,
lot_id uuid not null,
cycle_id uuid not null,
evidence_id text not null references signal_engine.evidence_snapshot(evidence_id),
action text not null,
sell_fraction numeric(9,6) not null check (sell_fraction between 0 and 1),
policy_id text not null,
priority integer not null,
reason_code text not null,
reentry_eligible boolean not null,
created_at timestamptz not null,
decision_hash text not null unique
);
create table if not exists signal_engine.reentry_watch (
watch_id uuid primary key,
sell_decision_id uuid not null unique references signal_engine.signal_decision(decision_id),
prior_cycle_id uuid not null,
state text not null,
minimum_wait_sessions integer not null check (minimum_wait_sessions >= 0),
minimum_spacing_sessions integer not null check (minimum_spacing_sessions >= 0),
expires_after_sessions integer not null check (expires_after_sessions > 0),
created_at timestamptz not null
);
create table if not exists signal_engine.reentry_stage (
watch_id uuid not null references signal_engine.reentry_watch(watch_id),
stage_no integer not null,
target_fraction numeric(9,6) not null check (target_fraction > 0 and target_fraction <= 1),
status text not null,
eligible_at timestamptz null,
executed_cycle_id uuid null,
primary key (watch_id, stage_no)
);
create or replace function signal_engine.prevent_immutable_change()
returns trigger language plpgsql as $$
begin
raise exception 'immutable evidence/decision rows cannot be updated or deleted';
end;
$$;
drop trigger if exists evidence_snapshot_immutable on signal_engine.evidence_snapshot;
create trigger evidence_snapshot_immutable
before update or delete on signal_engine.evidence_snapshot
for each row execute function signal_engine.prevent_immutable_change();
@@ -0,0 +1,24 @@
-- v11.1 hardening delta. Do not edit prior migrations.
create index if not exists ix_outbox_pending
on building_blocks.outbox_message (occurred_at, message_id)
where published_at is null;
create index if not exists ix_job_run_status_started
on building_blocks.job_run (status, started_at);
alter table signal_engine.signal_decision
add constraint ck_signal_decision_policy_id_not_blank
check (length(trim(policy_id)) > 0) not valid;
alter table signal_engine.signal_decision
validate constraint ck_signal_decision_policy_id_not_blank;
drop trigger if exists signal_decision_immutable on signal_engine.signal_decision;
create trigger signal_decision_immutable
before update or delete on signal_engine.signal_decision
for each row execute function signal_engine.prevent_immutable_change();
create unique index if not exists ux_reentry_stage_executed_cycle
on signal_engine.reentry_stage (executed_cycle_id)
where executed_cycle_id is not null;
@@ -0,0 +1,142 @@
-- v12.0 integrated hardening delta. Prior migrations remain immutable.
-- Rename ambiguous columns while preserving existing data.
do $$
begin
if exists (
select 1 from information_schema.columns
where table_schema = 'signal_engine'
and table_name = 'signal_decision'
and column_name = 'lot_id'
) and not exists (
select 1 from information_schema.columns
where table_schema = 'signal_engine'
and table_name = 'signal_decision'
and column_name = 'position_lot_id'
) then
alter table signal_engine.signal_decision
rename column lot_id to position_lot_id;
end if;
if exists (
select 1 from information_schema.columns
where table_schema = 'signal_engine'
and table_name = 'signal_decision'
and column_name = 'sell_fraction'
) and not exists (
select 1 from information_schema.columns
where table_schema = 'signal_engine'
and table_name = 'signal_decision'
and column_name = 'sell_ratio_of_lot'
) then
alter table signal_engine.signal_decision
rename column sell_fraction to sell_ratio_of_lot;
end if;
end;
$$;
alter table signal_engine.signal_decision
add column if not exists target_portfolio_weight_after numeric(12,8),
add column if not exists dataset_id text,
add column if not exists model_version text,
add column if not exists config_version text,
add column if not exists code_sha text,
add column if not exists idempotency_key text,
add column if not exists correlation_id text;
update signal_engine.signal_decision d
set dataset_id = coalesce(d.dataset_id, e.dataset_id),
model_version = coalesce(d.model_version, e.model_version),
config_version = coalesce(d.config_version, e.config_version),
code_sha = coalesce(d.code_sha, 'LEGACY_UNKNOWN'),
target_portfolio_weight_after = coalesce(d.target_portfolio_weight_after, 0),
idempotency_key = coalesce(d.idempotency_key, 'legacy:' || d.decision_id::text),
correlation_id = coalesce(d.correlation_id, 'legacy:' || d.decision_id::text)
from signal_engine.evidence_snapshot e
where e.evidence_id = d.evidence_id;
alter table signal_engine.signal_decision
alter column target_portfolio_weight_after set not null,
alter column dataset_id set not null,
alter column model_version set not null,
alter column config_version set not null,
alter column code_sha set not null,
alter column idempotency_key set not null,
alter column correlation_id set not null;
alter table signal_engine.signal_decision
drop constraint if exists ck_signal_decision_sell_ratio_of_lot,
add constraint ck_signal_decision_sell_ratio_of_lot
check (sell_ratio_of_lot between 0 and 1),
drop constraint if exists ck_signal_decision_target_weight,
add constraint ck_signal_decision_target_weight
check (target_portfolio_weight_after between 0 and 1);
create unique index if not exists ux_signal_decision_idempotency
on signal_engine.signal_decision (idempotency_key);
create index if not exists ix_signal_decision_lot_created
on signal_engine.signal_decision (position_lot_id, created_at desc);
-- Rebuildable, versioned read model. It is populated only by approved upstream slices.
create table if not exists signal_engine.sell_decision_context (
context_id uuid primary key,
position_lot_id uuid not null,
cycle_id uuid not null,
evidence_id text not null references signal_engine.evidence_snapshot(evidence_id),
dataset_id text not null,
model_version text not null,
config_version text not null,
code_sha text not null,
as_of timestamptz not null,
published_at_cutoff timestamptz not null,
current_portfolio_weight numeric(12,8) not null
check (current_portfolio_weight between 0 and 1),
strategic_core_floor_weight numeric(12,8) not null
check (strategic_core_floor_weight between 0 and current_portfolio_weight),
hard_impairment_approved boolean not null,
capital_floor_breached boolean not null,
survival_sell_ratio_of_lot numeric(12,8) not null
check (survival_sell_ratio_of_lot between 0 and 1),
gap_below_floor_atr numeric(18,8) not null check (gap_below_floor_atr >= 0),
consecutive_close_breaches integer not null check (consecutive_close_breaches >= 0),
cooldown_satisfied boolean not null,
concentration_sell_ratio_of_lot numeric(12,8) not null
check (concentration_sell_ratio_of_lot between 0 and 1),
opportunity_edge_lower_bound numeric(18,8) not null,
opportunity_sell_ratio_of_lot numeric(12,8) not null
check (opportunity_sell_ratio_of_lot between 0 and 1),
quality_status text not null check (quality_status in ('PASS', 'WARN', 'QUARANTINED')),
source_watermark text not null,
projection_version integer not null,
content_hash text not null unique,
created_at timestamptz not null default now(),
unique (position_lot_id, as_of, projection_version)
);
create index if not exists ix_sell_decision_context_lookup
on signal_engine.sell_decision_context (position_lot_id, as_of desc)
where quality_status = 'PASS';
drop trigger if exists sell_decision_context_immutable on signal_engine.sell_decision_context;
create trigger sell_decision_context_immutable
before update or delete on signal_engine.sell_decision_context
for each row execute function signal_engine.prevent_immutable_change();
-- Audit rows are append-only. Corrections are represented as new events.
create table if not exists signal_engine.decision_audit_event (
audit_event_id uuid primary key,
decision_id uuid not null references signal_engine.signal_decision(decision_id),
event_type text not null,
actor_id text not null,
correlation_id text not null,
payload_json jsonb not null,
payload_hash text not null,
occurred_at timestamptz not null,
unique (decision_id, event_type, payload_hash)
);
drop trigger if exists decision_audit_event_immutable on signal_engine.decision_audit_event;
create trigger decision_audit_event_immutable
before update or delete on signal_engine.decision_audit_event
for each row execute function signal_engine.prevent_immutable_change();
@@ -0,0 +1,68 @@
-- v12.1 execution-readiness delta. Prior migrations remain immutable.
alter table building_blocks.outbox_message
add column if not exists next_attempt_at timestamptz null,
add column if not exists lease_owner text null,
add column if not exists lease_until timestamptz null,
add column if not exists dead_lettered_at timestamptz null,
add column if not exists last_error_code text null;
create index if not exists ix_outbox_dispatchable
on building_blocks.outbox_message (coalesce(next_attempt_at, occurred_at), occurred_at, message_id)
where published_at is null and dead_lettered_at is null;
alter table building_blocks.inbox_message
add column if not exists processed_at timestamptz null,
add column if not exists result_hash text null;
create table if not exists building_blocks.projection_checkpoint (
projection_name text not null,
projection_version integer not null check (projection_version > 0),
source_watermark text not null,
last_event_id uuid null,
content_hash text not null,
built_at timestamptz not null,
primary key (projection_name, projection_version)
);
create table if not exists building_blocks.projection_rebuild_run (
rebuild_id uuid primary key,
projection_name text not null,
target_version integer not null check (target_version > 0),
through_watermark text not null,
dry_run boolean not null,
requested_by text not null,
requested_at timestamptz not null,
status text not null,
source_count bigint null,
projected_count bigint null,
result_hash text null,
finished_at timestamptz null,
error_code text null
);
create table if not exists building_blocks.audit_event (
audit_event_id uuid primary key,
entity_type text not null,
entity_id text not null,
event_type text not null,
actor_id text not null,
correlation_id text not null,
payload_json jsonb not null,
payload_hash text not null,
corrects_audit_event_id uuid null references building_blocks.audit_event(audit_event_id),
occurred_at timestamptz not null,
unique (entity_type, entity_id, event_type, payload_hash)
);
create or replace function building_blocks.prevent_append_only_change()
returns trigger language plpgsql as $$
begin
raise exception 'append-only row cannot be updated or deleted';
end;
$$;
drop trigger if exists audit_event_append_only on building_blocks.audit_event;
create trigger audit_event_append_only
before update or delete on building_blocks.audit_event
for each row execute function building_blocks.prevent_append_only_change();
@@ -0,0 +1,61 @@
-- v12.2 strategic data-correctness delta.
-- Prior columns remain for compatibility; new code uses explicit security/lot weight semantics.
alter table signal_engine.sell_decision_context
add column if not exists current_security_portfolio_weight numeric(12,8),
add column if not exists current_lot_portfolio_weight numeric(12,8);
update signal_engine.sell_decision_context
set current_security_portfolio_weight = coalesce(current_security_portfolio_weight, current_portfolio_weight),
current_lot_portfolio_weight = coalesce(current_lot_portfolio_weight, current_portfolio_weight)
where current_security_portfolio_weight is null
or current_lot_portfolio_weight is null;
alter table signal_engine.sell_decision_context
alter column current_security_portfolio_weight set not null,
alter column current_lot_portfolio_weight set not null,
drop constraint if exists ck_sell_context_security_weight,
add constraint ck_sell_context_security_weight
check (current_security_portfolio_weight between 0 and 1),
drop constraint if exists ck_sell_context_lot_weight,
add constraint ck_sell_context_lot_weight
check (current_lot_portfolio_weight between 0 and current_security_portfolio_weight),
drop constraint if exists ck_sell_context_published_cutoff,
add constraint ck_sell_context_published_cutoff
check (published_at_cutoff <= as_of);
comment on column signal_engine.sell_decision_context.current_portfolio_weight is
'Legacy ambiguous field. Do not use in v12.2+ decisions.';
comment on column signal_engine.sell_decision_context.current_security_portfolio_weight is
'Absolute portfolio weight of the security, 0..1.';
comment on column signal_engine.sell_decision_context.current_lot_portfolio_weight is
'Absolute portfolio weight represented by the target PositionLot, 0..security weight.';
alter table signal_engine.signal_decision
add column if not exists target_security_portfolio_weight_after numeric(12,8),
add column if not exists policy_trace_json jsonb;
update signal_engine.signal_decision
set target_security_portfolio_weight_after = coalesce(
target_security_portfolio_weight_after,
target_portfolio_weight_after,
0),
policy_trace_json = coalesce(policy_trace_json, '[]'::jsonb)
where target_security_portfolio_weight_after is null
or policy_trace_json is null;
alter table signal_engine.signal_decision
alter column target_security_portfolio_weight_after set not null,
alter column policy_trace_json set not null,
drop constraint if exists ck_signal_decision_target_security_weight,
add constraint ck_signal_decision_target_security_weight
check (target_security_portfolio_weight_after between 0 and 1),
drop constraint if exists ck_signal_decision_policy_trace_array,
add constraint ck_signal_decision_policy_trace_array
check (jsonb_typeof(policy_trace_json) = 'array');
comment on column signal_engine.signal_decision.target_portfolio_weight_after is
'Legacy ambiguous target field. v12.2+ uses target_security_portfolio_weight_after.';
create index if not exists ix_signal_decision_policy_trace_gin
on signal_engine.signal_decision using gin (policy_trace_json);
@@ -0,0 +1,149 @@
-- v12.3 semantic-versioning and contract-governance delta.
-- Prior migrations remain immutable. Legacy ambiguous weight contexts are blocked, not guessed.
alter table signal_engine.sell_decision_context
add column if not exists weight_semantics_version smallint;
-- Every row created before this migration is conservatively classified as legacy/ambiguous.
update signal_engine.sell_decision_context
set weight_semantics_version = 1
where weight_semantics_version is null;
alter table signal_engine.sell_decision_context
alter column weight_semantics_version set default 2,
alter column weight_semantics_version set not null,
drop constraint if exists ck_sell_context_weight_semantics_version,
add constraint ck_sell_context_weight_semantics_version
check (weight_semantics_version in (1, 2));
comment on column signal_engine.sell_decision_context.weight_semantics_version is
'1=legacy ambiguous current_portfolio_weight backfill; 2=explicit security and lot weights from approved source. Decision reads require 2.';
alter table signal_engine.signal_decision
add column if not exists decision_contract_version text,
add column if not exists policy_trace_schema_version smallint;
update signal_engine.signal_decision
set decision_contract_version = coalesce(decision_contract_version, 'sell-decision.v2'),
policy_trace_schema_version = coalesce(policy_trace_schema_version, 2)
where decision_contract_version is null
or policy_trace_schema_version is null;
alter table signal_engine.signal_decision
alter column decision_contract_version set default 'sell-decision.v2',
alter column decision_contract_version set not null,
alter column policy_trace_schema_version set default 2,
alter column policy_trace_schema_version set not null,
drop constraint if exists ck_signal_decision_contract_version,
add constraint ck_signal_decision_contract_version
check (decision_contract_version = 'sell-decision.v2'),
drop constraint if exists ck_signal_decision_policy_trace_schema_version,
add constraint ck_signal_decision_policy_trace_schema_version
check (policy_trace_schema_version = 2);
create table if not exists signal_engine.policy_contract_definition (
contract_version text primary key,
content_hash text not null unique,
policy_json jsonb not null,
status text not null check (status in ('PROPOSED', 'APPROVED', 'RETIRED')),
effective_from timestamptz null,
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null default now(),
check (jsonb_typeof(policy_json) = 'object')
);
insert into signal_engine.policy_contract_definition
(contract_version, content_hash, policy_json, status)
values
('sell-policy.v1', 'a269a0331b83c0f6ec108e7587de1d20c798036ff8d0c03d726cd854e73d8480', $policy$
{
"changeControl": "MODEL_CHANGE_AND_GOLDEN_OOS_REQUIRED",
"contractVersion": "sell-policy.v1",
"decisionContractVersion": "sell-decision.v2",
"policies": [
{
"condition": "approved hard impairment",
"documentedRange": [
0.8,
1.0
],
"mayCrossStrategicCore": true,
"policyId": "ALG-SELL-001",
"priority": 1000,
"reentryEligible": false,
"requestedSellRatioOfLot": 1.0,
"terminal": true
},
{
"condition": "capital floor breached",
"decisionRequired": "Whether portfolio survival bypasses same-direction cooldown",
"mayCrossStrategicCore": true,
"policyId": "ALG-SELL-PORT-001",
"priority": 900,
"ratioSource": "server PIT risk context",
"reentryEligible": true,
"terminal": true
},
{
"condition": {
"gapBelowFloorAtrGte": 1.5
},
"documentedRange": [
0.3,
0.5
],
"mayCrossStrategicCore": false,
"policyId": "ALG-SELL-002",
"priority": 800,
"reentryEligible": true,
"requestedSellRatioOfLot": 0.4,
"terminal": false
},
{
"condition": {
"consecutiveCloseBreachesGte": 2
},
"documentedRange": [
0.15,
0.25
],
"mayCrossStrategicCore": false,
"policyId": "ALG-SELL-003",
"priority": 700,
"reentryEligible": true,
"requestedSellRatioOfLot": 0.2,
"terminal": false
},
{
"condition": "approved concentration/liquidity excess ratio > 0",
"mayCrossStrategicCore": false,
"policyId": "ALG-SELL-004",
"priority": 600,
"ratioSource": "server PIT portfolio risk context",
"reentryEligible": true,
"terminal": false
},
{
"condition": "opportunity edge lower bound > 0 and requested ratio > 0",
"mayCrossStrategicCore": false,
"policyId": "ALG-SELL-005",
"priority": 500,
"reentryEligible": true,
"requestedRange": [
0.1,
0.25
],
"terminal": false
}
],
"policyTraceSchemaVersion": 2,
"status": "RESEARCH_CANDIDATE_NOT_PRODUCTION"
}
$policy$::jsonb, 'PROPOSED')
on conflict (contract_version) do nothing;
drop trigger if exists policy_contract_definition_immutable on signal_engine.policy_contract_definition;
create trigger policy_contract_definition_immutable
before update or delete on signal_engine.policy_contract_definition
for each row execute function signal_engine.prevent_immutable_change();
@@ -0,0 +1,264 @@
-- v12.4 continuous model operations delta.
-- Evaluation and proposal automation only. This migration does not enable automatic model promotion,
-- automatic order submission or KIS submission.
create schema if not exists evaluation;
create schema if not exists governance;
create table if not exists evaluation.dataset_manifest (
dataset_id text primary key,
scope_key text not null,
content_hash text not null unique,
source_catalog_version text not null,
lineage_hash text not null,
status text not null check (status in ('PROPOSED', 'APPROVED', 'QUARANTINED', 'RETIRED')),
frozen_at timestamptz not null,
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null default now()
);
create index if not exists ix_dataset_manifest_scope_frozen
on evaluation.dataset_manifest (scope_key, frozen_at desc)
where status = 'APPROVED';
create table if not exists governance.model_version_registry (
model_version text not null,
scope_key text not null,
config_version text not null,
code_sha text not null,
contract_version text not null,
lifecycle_state text not null check (lifecycle_state in
('RESEARCH', 'CHALLENGER', 'SHADOW', 'CANDIDATE', 'APPROVED', 'RETIRED', 'ROLLED_BACK')),
effective_at timestamptz not null,
retired_at timestamptz null,
model_card_hash text not null,
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null default now(),
primary key (model_version, scope_key, effective_at),
check (lifecycle_state <> 'APPROVED' or (approved_by is not null and approved_at is not null))
);
create index if not exists ix_model_version_registry_active
on governance.model_version_registry (scope_key, effective_at desc)
where lifecycle_state in ('RESEARCH', 'CHALLENGER', 'SHADOW', 'CANDIDATE', 'APPROVED');
create table if not exists evaluation.model_operation_schedule (
schedule_id uuid primary key,
operation_code text not null,
operation_name text not null,
scope_key text not null,
cadence text not null check (cadence in ('DAILY', 'WEEKLY', 'MONTHLY', 'QUARTERLY', 'EVENT_DRIVEN')),
automation_mode text not null check (automation_mode in ('EVALUATION_ONLY', 'PROPOSAL_ONLY', 'DRILL_ONLY')),
queue_name text not null,
schedule_version integer not null check (schedule_version > 0),
enabled boolean not null default true,
next_due_at timestamptz not null,
last_dispatched_at timestamptz null,
last_background_job_id text null,
max_lag interval not null,
primary_owner text not null,
secondary_owner text not null,
lease_owner text null,
lease_until timestamptz null,
last_error_code text null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (operation_code, scope_key, schedule_version)
);
create index if not exists ix_model_operation_schedule_due
on evaluation.model_operation_schedule (next_due_at, operation_code, scope_key)
where enabled = true;
create table if not exists evaluation.model_operation_request (
request_id uuid primary key,
schedule_id uuid not null references evaluation.model_operation_schedule(schedule_id),
operation_code text not null,
scope_key text not null,
automation_mode text not null check (automation_mode in ('EVALUATION_ONLY', 'PROPOSAL_ONLY', 'DRILL_ONLY')),
idempotency_key text not null unique,
dataset_id text not null,
data_hash text not null,
model_version text not null,
config_version text not null,
code_sha text not null,
contract_version text not null,
lifecycle_state text not null,
correlation_id text not null,
status text not null check (status in ('REQUESTED', 'RUNNING', 'SUCCEEDED', 'BUSINESS_HOLD', 'FAILED', 'QUARANTINED')),
output_hash text null,
error_code text null,
requested_at timestamptz not null,
started_at timestamptz null,
finished_at timestamptz null
);
create index if not exists ix_model_operation_request_scope_time
on evaluation.model_operation_request (scope_key, operation_code, requested_at desc);
-- Request is a lifecycle aggregate: status/timing fields are mutable under optimistic/transactional control.
-- Every transition is additionally recorded as an immutable status event so operational history is never lost.
create table if not exists evaluation.model_operation_status_event (
event_id uuid primary key,
request_id uuid not null references evaluation.model_operation_request(request_id),
from_status text null,
to_status text not null check (to_status in
('REQUESTED', 'RUNNING', 'SUCCEEDED', 'BUSINESS_HOLD', 'FAILED', 'QUARANTINED')),
reason_code text null,
payload_hash text not null,
actor_type text not null check (actor_type in ('SYSTEM', 'OPERATOR', 'REPLAY')),
correlation_id text not null,
occurred_at timestamptz not null,
created_at timestamptz not null default now(),
unique (request_id, to_status, occurred_at, payload_hash)
);
create index if not exists ix_model_operation_status_event_request_time
on evaluation.model_operation_status_event (request_id, occurred_at);
create table if not exists evaluation.model_metric_definition (
metric_code text not null,
definition_version integer not null check (definition_version > 0),
numerator_definition text not null,
denominator_definition text not null,
evaluation_window text not null,
aggregation_method text not null,
threshold_json jsonb not null,
status text not null check (status in ('PROPOSED', 'APPROVED', 'RETIRED')),
content_hash text not null,
effective_from timestamptz null,
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null default now(),
primary key (metric_code, definition_version),
unique (content_hash)
);
create table if not exists evaluation.model_metric_observation (
observation_id uuid primary key,
request_id uuid not null references evaluation.model_operation_request(request_id),
metric_code text not null,
definition_version integer not null,
scope_key text not null,
cohort_key text not null,
value_numeric numeric(30, 12) null,
value_text text null,
sample_size bigint not null check (sample_size >= 0),
dataset_id text not null,
model_version text not null,
as_of timestamptz not null,
content_hash text not null,
created_at timestamptz not null default now(),
foreign key (metric_code, definition_version)
references evaluation.model_metric_definition(metric_code, definition_version),
check ((value_numeric is null) <> (value_text is null)),
unique (request_id, metric_code, definition_version, cohort_key, content_hash)
);
create table if not exists evaluation.model_evaluation_snapshot (
snapshot_id uuid primary key,
request_id uuid not null references evaluation.model_operation_request(request_id),
scope_key text not null,
model_version text not null,
dataset_id text not null,
gate_contract_version text not null,
gate_decision text not null check (gate_decision in ('PASS', 'WARN', 'HOLD', 'FAIL')),
blocking_reasons_json jsonb not null,
warnings_json jsonb not null,
evidence_hash text not null,
as_of timestamptz not null,
created_at timestamptz not null default now(),
unique (request_id, evidence_hash)
);
create table if not exists governance.model_improvement_proposal (
proposal_id uuid primary key,
source_request_id uuid not null references evaluation.model_operation_request(request_id),
scope_key text not null,
base_model_version text not null,
proposal_type text not null check (proposal_type in
('DATA_REMEDIATION', 'FEATURE_REVIEW', 'THRESHOLD_REVIEW', 'POLICY_REFACTORING',
'CALIBRATION_REVIEW', 'RISK_LIMIT_REVIEW', 'TECH_DEBT_REPAYMENT')),
problem_statement text not null,
supporting_evidence_json jsonb not null,
counter_evidence_json jsonb not null,
expected_benefit text not null,
risks text not null,
required_tests_json jsonb not null,
status text not null check (status in
('DRAFT', 'REVIEW_REQUIRED', 'APPROVED_FOR_RESEARCH', 'REJECTED', 'EXPIRED')),
created_by text not null,
created_at timestamptz not null,
reviewed_by text null,
reviewed_at timestamptz null,
expires_at timestamptz not null,
content_hash text not null unique,
check (status <> 'APPROVED_FOR_RESEARCH' or (reviewed_by is not null and reviewed_at is not null))
);
create table if not exists governance.model_promotion_review (
review_id uuid primary key,
scope_key text not null,
candidate_model_version text not null,
evidence_snapshot_id uuid not null references evaluation.model_evaluation_snapshot(snapshot_id),
independent_validation_hash text not null,
compliance_review_hash text null,
security_review_hash text null,
decision text not null check (decision in ('PENDING', 'APPROVED_FOR_SHADOW', 'APPROVED_FOR_PILOT', 'REJECTED', 'EXPIRED')),
maker_id text not null,
checker_id text null,
created_at timestamptz not null,
decided_at timestamptz null,
check (maker_id <> coalesce(checker_id, '')),
check (decision = 'PENDING' or (checker_id is not null and decided_at is not null))
);
create table if not exists governance.model_rollback_drill (
drill_id uuid primary key,
scope_key text not null,
champion_model_version text not null,
fallback_model_version text not null,
runbook_version text not null,
started_at timestamptz not null,
finished_at timestamptz null,
result text not null check (result in ('RUNNING', 'PASS', 'FAIL', 'BUSINESS_HOLD')),
recovery_time_seconds integer null check (recovery_time_seconds is null or recovery_time_seconds >= 0),
evidence_hash text null,
owner text not null,
secondary_owner text not null
);
-- Append-only evidence. Request status is mutable, but status_event/observation/snapshot history is immutable.
drop trigger if exists model_operation_status_event_append_only on evaluation.model_operation_status_event;
create trigger model_operation_status_event_append_only
before update or delete on evaluation.model_operation_status_event
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_metric_observation_append_only on evaluation.model_metric_observation;
create trigger model_metric_observation_append_only
before update or delete on evaluation.model_metric_observation
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_evaluation_snapshot_append_only on evaluation.model_evaluation_snapshot;
create trigger model_evaluation_snapshot_append_only
before update or delete on evaluation.model_evaluation_snapshot
for each row execute function building_blocks.prevent_append_only_change();
-- Schedules intentionally automate evidence collection/proposal generation only.
insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner)
values
('e4100000-0000-4000-8000-000000000010', 'J10', 'OutcomeEvaluationRun', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-evaluation', 1, true, now() + interval '1 hour', interval '1 day', 'Quant/Ops', 'Data/QA'),
('e4100000-0000-4000-8000-000000000011', 'J11', 'DailyScorecardBuild', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-evaluation', 1, true, now() + interval '2 hours', interval '1 day', 'Quant/Ops', 'Risk/SRE'),
('e4100000-0000-4000-8000-000000000017', 'J17', 'DriftDetectionRun', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-evaluation', 1, true, now() + interval '3 hours', interval '1 day', 'Quant/Risk', 'Data/SRE'),
('e4100000-0000-4000-8000-000000000018', 'J18', 'ChampionChallengerEvaluation', 'GLOBAL', 'WEEKLY', 'EVALUATION_ONLY', 'q-evaluation', 1, true, now() + interval '1 day', interval '7 days', 'Quant/Risk', 'QA/InvestmentCommittee'),
('e4100000-0000-4000-8000-000000000019', 'J19', 'FrozenOosBacktest', 'GLOBAL', 'MONTHLY', 'EVALUATION_ONLY', 'q-research', 1, true, now() + interval '7 days', interval '31 days', 'Quant/Data', 'QA/Risk'),
('e4100000-0000-4000-8000-000000000020', 'J20', 'RobustnessPboDsrRun', 'GLOBAL', 'QUARTERLY', 'EVALUATION_ONLY', 'q-research', 1, true, now() + interval '30 days', interval '95 days', 'Quant/Risk', 'IndependentValidation'),
('e4100000-0000-4000-8000-000000000021', 'J21', 'ModelImprovementProposalBuild', 'GLOBAL', 'MONTHLY', 'PROPOSAL_ONLY', 'q-research', 1, true, now() + interval '14 days', interval '31 days', 'Quant Lead', 'Risk/Architect'),
('e4100000-0000-4000-8000-000000000022', 'J22', 'PromotionEvidenceReviewBuild', 'GLOBAL', 'MONTHLY', 'PROPOSAL_ONLY', 'q-control', 1, true, now() + interval '21 days', interval '31 days', 'Risk/InvestmentCommittee', 'Compliance/QA'),
('e4100000-0000-4000-8000-000000000023', 'J23', 'ModelRollbackDrill', 'GLOBAL', 'QUARTERLY', 'DRILL_ONLY', 'q-control', 1, true, now() + interval '45 days', interval '95 days', 'SRE/Risk', 'Module Owner/QA'),
('e4100000-0000-4000-8000-000000000024', 'J24', 'DataRevisionRevalidation', 'GLOBAL', 'WEEKLY', 'EVALUATION_ONLY', 'q-backfill', 1, true, now() + interval '2 days', interval '7 days', 'Data/Quant', 'DBA/QA')
on conflict (operation_code, scope_key, schedule_version) do nothing;
+137
View File
@@ -0,0 +1,137 @@
-- v12.5 execution assurance delta.
-- This migration adds evidence and scheduling metadata only. It does not enable automatic model mutation,
-- client publication, broker submission or model promotion.
-- Fail closed after upgrade. Each schedule must be enabled by an approved operational change.
update evaluation.model_operation_schedule
set enabled = false,
updated_at = now(),
last_error_code = 'V12_5_REAPPROVAL_REQUIRED'
where schedule_version = 1
and operation_code in ('J10','J11','J17','J18','J19','J20','J21','J22','J23','J24');
alter table evaluation.model_operation_schedule
add column if not exists calendar_id text not null default 'GLOBAL_UTC',
add column if not exists due_policy text not null default 'FIXED_CADENCE',
add column if not exists dependency_json jsonb not null default '[]'::jsonb,
add column if not exists catch_up_policy text not null default 'LATEST_ONLY',
add column if not exists max_catch_up integer not null default 1 check (max_catch_up between 0 and 31),
add column if not exists business_hold_code text null;
create table if not exists evaluation.model_operation_artifact (
artifact_id uuid primary key,
request_id uuid not null references evaluation.model_operation_request(request_id),
artifact_type text not null,
artifact_uri text not null,
content_hash text not null,
media_type text not null,
evidence_class text not null check (evidence_class in ('SOURCE', 'RUNTIME', 'RESEARCH', 'RELEASE', 'AUDIT')),
produced_by text not null,
produced_at timestamptz not null,
retention_until timestamptz null,
created_at timestamptz not null default now(),
unique (request_id, artifact_type, content_hash)
);
create table if not exists evaluation.model_operation_dependency_result (
dependency_result_id uuid primary key,
request_id uuid not null references evaluation.model_operation_request(request_id),
dependency_code text not null,
result text not null check (result in ('PASS', 'WARN', 'HOLD', 'FAIL')),
evidence_hash text not null,
checked_at timestamptz not null,
unique (request_id, dependency_code, evidence_hash)
);
create table if not exists governance.release_evidence_bundle (
bundle_id uuid primary key,
release_version text not null,
source_manifest_hash text not null,
build_artifact_hash text null,
test_artifact_hash text null,
migration_artifact_hash text null,
security_artifact_hash text null,
rollback_artifact_hash text null,
decision_log_hash text not null,
status text not null check (status in ('DRAFT', 'REVIEW_REQUIRED', 'APPROVED', 'REJECTED', 'EXPIRED')),
maker_id text not null,
checker_id text null,
created_at timestamptz not null,
decided_at timestamptz null,
content_hash text not null unique,
check (status not in ('APPROVED', 'REJECTED') or (checker_id is not null and checker_id <> maker_id and decided_at is not null))
);
create table if not exists governance.source_contract_snapshot (
snapshot_id uuid primary key,
source_code text not null,
schema_version text not null,
license_version text not null,
sla_version text not null,
timezone_contract text not null,
unit_contract text not null,
content_hash text not null unique,
status text not null check (status in ('PROPOSED', 'APPROVED', 'RETIRED', 'QUARANTINED')),
effective_from timestamptz null,
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null default now()
);
create table if not exists governance.execution_assurance_decision (
decision_id uuid primary key,
decision_code text not null,
scope_key text not null,
decision_version integer not null check (decision_version > 0),
status text not null check (status in ('DECISION_REQUIRED', 'APPROVED', 'REJECTED', 'SUPERSEDED', 'EXPIRED')),
statement text not null,
basis_json jsonb not null,
owner text not null,
approved_by text null,
approved_at timestamptz null,
expires_at timestamptz null,
content_hash text not null,
created_at timestamptz not null default now(),
unique (decision_code, scope_key, decision_version),
unique (content_hash)
);
-- Append-only operational evidence.
drop trigger if exists model_operation_artifact_append_only on evaluation.model_operation_artifact;
create trigger model_operation_artifact_append_only
before update or delete on evaluation.model_operation_artifact
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_operation_dependency_result_append_only on evaluation.model_operation_dependency_result;
create trigger model_operation_dependency_result_append_only
before update or delete on evaluation.model_operation_dependency_result
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists release_evidence_bundle_append_only on governance.release_evidence_bundle;
create trigger release_evidence_bundle_append_only
before update or delete on governance.release_evidence_bundle
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists source_contract_snapshot_append_only on governance.source_contract_snapshot;
create trigger source_contract_snapshot_append_only
before update or delete on governance.source_contract_snapshot
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists execution_assurance_decision_append_only on governance.execution_assurance_decision;
create trigger execution_assurance_decision_append_only
before update or delete on governance.execution_assurance_decision
for each row execute function building_blocks.prevent_append_only_change();
-- Additional checks are seeded disabled. They may be enabled only after their source/calendar/SLO contracts are approved.
insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner,
calendar_id, due_policy, dependency_json, catch_up_policy, max_catch_up)
values
('e4100000-0000-4000-8000-000000000025', 'J25', 'SourceContractDriftCheck', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-evaluation', 1, false, now() + interval '1 day', interval '1 day', 'Data Governance', 'Adapter Owner/QA', 'GLOBAL_UTC', 'FIXED_CADENCE', '["SOURCE_CONTRACT_APPROVED"]', 'LATEST_ONLY', 1),
('e4100000-0000-4000-8000-000000000026', 'J26', 'MarketCalendarCompletenessCheck', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-market-data', 1, false, now() + interval '1 day', interval '1 day', 'Data/Ops', 'Quant/QA', 'APPROVED_MARKET_CALENDAR', 'TRADING_SESSION', '["MARKET_CALENDAR_APPROVED","SOURCE_COMPLETE"]', 'LATEST_ONLY', 1),
('e4100000-0000-4000-8000-000000000027', 'J27', 'EvidenceChainAudit', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-control', 1, false, now() + interval '1 day', interval '1 day', 'Compliance/QA', 'Data/BE', 'GLOBAL_UTC', 'FIXED_CADENCE', '["AUDIT_LEDGER_READY"]', 'LATEST_ONLY', 1),
('e4100000-0000-4000-8000-000000000028', 'J28', 'ProjectionFreshnessCheck', 'GLOBAL', 'DAILY', 'EVALUATION_ONLY', 'q-evaluation', 1, false, now() + interval '1 day', interval '1 day', 'BE/Data', 'SRE/QA', 'GLOBAL_UTC', 'FIXED_CADENCE', '["PROJECTION_CONTRACT_APPROVED"]', 'LATEST_ONLY', 1),
('e4100000-0000-4000-8000-000000000029', 'J29', 'CapacitySlaTrend', 'GLOBAL', 'WEEKLY', 'EVALUATION_ONLY', 'q-control', 1, false, now() + interval '7 days', interval '7 days', 'SRE/PM', 'DBA/Module Owner', 'GLOBAL_UTC', 'FIXED_CADENCE', '["SLO_APPROVED","VOLUME_ASSUMPTION_APPROVED"]', 'LATEST_ONLY', 1),
('e4100000-0000-4000-8000-000000000030', 'J30', 'ReleaseEvidenceAssemble', 'GLOBAL', 'EVENT_DRIVEN', 'PROPOSAL_ONLY', 'q-control', 1, false, now() + interval '365 days', interval '365 days', 'QA/Release Manager', 'Compliance/SRE', 'GLOBAL_UTC', 'EVENT', '["BUILD_GREEN","TEST_GREEN","MIGRATION_GREEN","SECURITY_GREEN","ROLLBACK_READY"]', 'NONE', 0)
on conflict (operation_code, scope_key, schedule_version) do nothing;
@@ -0,0 +1,73 @@
-- v13.0 continuous model feedback loop. All schedules are inserted disabled and are evidence/proposal only.
create table if not exists evaluation.prediction_freeze (
prediction_freeze_id uuid primary key,
portfolio_scope text not null,
market_session date not null,
as_of timestamptz not null,
dataset_id text not null,
model_version text not null,
config_version text not null,
code_sha text not null,
contract_version text not null,
content_hash text not null unique,
frozen_at timestamptz not null default now(),
unique (portfolio_scope, market_session, model_version, content_hash)
);
create table if not exists evaluation.evaluation_window_maturity (
maturity_id uuid primary key,
decision_id uuid not null,
window_sessions integer not null check (window_sessions in (1,5,20,63,126,252)),
due_session date not null,
maturity_revision integer not null check (maturity_revision > 0),
status text not null check (status in ('PENDING','MATURED','HELD_DATA','EVALUATED','SUPERSEDED')),
dataset_id text not null,
supersedes_maturity_id uuid null references evaluation.evaluation_window_maturity(maturity_id),
content_hash text not null unique,
created_at timestamptz not null default now(),
check (supersedes_maturity_id is null or supersedes_maturity_id <> maturity_id),
unique (decision_id, window_sessions, dataset_id, maturity_revision)
);
create table if not exists governance.model_improvement_hypothesis (
hypothesis_id uuid primary key,
model_version text not null,
hypothesis_version integer not null check (hypothesis_version > 0),
problem_statement text not null,
evidence_json jsonb not null,
proposed_change text not null,
expected_effect text not null,
falsification_test text not null,
non_goals text not null,
status text not null check (status in ('DRAFT','REVIEW_REQUIRED','APPROVED_FOR_EXPERIMENT','REJECTED','SUPERSEDED','EXPIRED')),
maker_id text not null,
checker_id text null,
supersedes_hypothesis_id uuid null references governance.model_improvement_hypothesis(hypothesis_id),
expires_at timestamptz not null,
content_hash text not null unique,
created_at timestamptz not null default now(),
decided_at timestamptz null,
check (supersedes_hypothesis_id is null or supersedes_hypothesis_id <> hypothesis_id),
check (status not in ('APPROVED_FOR_EXPERIMENT','REJECTED') or (checker_id is not null and checker_id <> maker_id and decided_at is not null)),
unique (model_version, hypothesis_version)
);
drop trigger if exists prediction_freeze_append_only on evaluation.prediction_freeze;
create trigger prediction_freeze_append_only before update or delete on evaluation.prediction_freeze for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists evaluation_window_maturity_append_only on evaluation.evaluation_window_maturity;
create trigger evaluation_window_maturity_append_only before update or delete on evaluation.evaluation_window_maturity for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_improvement_hypothesis_append_only on governance.model_improvement_hypothesis;
create trigger model_improvement_hypothesis_append_only before update or delete on governance.model_improvement_hypothesis for each row execute function building_blocks.prevent_append_only_change();
insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner,
calendar_id, due_policy, dependency_json, catch_up_policy, max_catch_up)
values
('e4100000-0000-4000-8000-000000000031','J31','PredictionFreezeRun','GLOBAL','DAILY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '1 day',interval '1 day','Quant/Data','QA/Risk','APPROVED_MARKET_CALENDAR','TRADING_SESSION','["PIT_CONTEXT_APPROVED","MODEL_CONTEXT_APPROVED"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000032','J32','OutcomeMaturitySweep','GLOBAL','DAILY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '1 day',interval '1 day','Quant/Ops','Data/QA','APPROVED_MARKET_CALENDAR','TRADING_SESSION','["TOTAL_RETURN_COMPLETE","CALENDAR_APPROVED"]','BOUNDED',7),
('e4100000-0000-4000-8000-000000000033','J33','SellReentryAttributionReview','GLOBAL','WEEKLY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '7 days',interval '7 days','Quant/Risk','Advisor/QA','GLOBAL_UTC','FIXED_CADENCE','["OUTCOME_MATURED","METRIC_CONTRACT_APPROVED"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000034','J34','CalibrationRegimeReview','GLOBAL','WEEKLY','EVALUATION_ONLY','q-evaluation',2,false,now()+interval '7 days',interval '7 days','Quant/Risk','Data/IndependentValidation','GLOBAL_UTC','FIXED_CADENCE','["COHORT_VERSION_APPROVED","REGIME_DEFINITION_APPROVED"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000035','J35','ImprovementHypothesisBuild','GLOBAL','MONTHLY','PROPOSAL_ONLY','q-research',2,false,now()+interval '30 days',interval '30 days','Quant Lead','Risk/Architect','GLOBAL_UTC','FIXED_CADENCE','["SCORECARD_COMPLETE","ATTRIBUTION_COMPLETE","DEBT_REGISTER_CURRENT"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000036','J36','ChallengerExperimentPlan','GLOBAL','MONTHLY','PROPOSAL_ONLY','q-research',2,false,now()+interval '30 days',interval '30 days','Quant Lead','IndependentValidation/QA','GLOBAL_UTC','FIXED_CADENCE','["HYPOTHESIS_APPROVED_FOR_EXPERIMENT","EXPERIMENT_REGISTRY_READY"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000037','J37','IndependentValidationPack','GLOBAL','QUARTERLY','PROPOSAL_ONLY','q-control',2,false,now()+interval '90 days',interval '90 days','IndependentValidation','Risk/Compliance','GLOBAL_UTC','FIXED_CADENCE','["OOS_COMPLETE","PBO_DSR_COMPLETE","REPRODUCIBILITY_COMPLETE"]','LATEST_ONLY',1),
('e4100000-0000-4000-8000-000000000038','J38','ModelPolicyDebtReview','GLOBAL','MONTHLY','PROPOSAL_ONLY','q-control',2,false,now()+interval '30 days',interval '30 days','Risk/Architect','Quant/PM','GLOBAL_UTC','FIXED_CADENCE','["DEBT_REGISTER_CURRENT","INCIDENT_REVIEW_COMPLETE"]','LATEST_ONLY',1)
on conflict (operation_code, scope_key, schedule_version) do nothing;
@@ -0,0 +1,97 @@
-- v14.0 governed feedback-cycle delta.
-- This migration formalizes evidence-to-hypothesis-to-independent-validation history.
-- It does not enable automatic model activation, client publication, automatic order submission or KIS submission.
create table if not exists evaluation.model_feedback_cycle (
cycle_id uuid primary key,
scope_key text not null,
base_model_version text not null,
state text not null check (state in (
'PLANNED','PREDICTION_FROZEN','OUTCOMES_MATURING','EVALUATED','IMPROVEMENT_PROPOSED',
'CHALLENGER_PLANNED','INDEPENDENTLY_VALIDATED','PROMOTION_REVIEW_PENDING','BUSINESS_HOLD','CLOSED')),
revision integer not null check (revision > 0),
started_at timestamptz not null,
closed_at timestamptz null,
last_evidence_hash text not null,
updated_at timestamptz not null,
check ((state = 'CLOSED') = (closed_at is not null))
);
create index if not exists ix_model_feedback_cycle_scope_state
on evaluation.model_feedback_cycle (scope_key, state, updated_at desc);
create table if not exists evaluation.model_feedback_transition (
transition_id uuid primary key,
cycle_id uuid not null references evaluation.model_feedback_cycle(cycle_id),
sequence_no integer not null check (sequence_no > 0),
from_state text not null,
to_state text not null,
reason_code text not null,
evidence_hash text not null,
actor_id text not null,
actor_type text not null check (actor_type in ('SYSTEM','OPERATOR','INDEPENDENT_VALIDATOR','INVESTMENT_COMMITTEE')),
correlation_id text not null,
occurred_at timestamptz not null,
content_hash text not null unique,
unique (cycle_id, sequence_no)
);
create table if not exists governance.model_hypothesis_evidence (
hypothesis_evidence_id uuid primary key,
hypothesis_id uuid not null references governance.model_improvement_hypothesis(hypothesis_id),
side text not null check (side in ('SUPPORTING','COUNTER')),
classification text not null check (classification in ('SOURCE','ASSUMPTION','UNKNOWN','DECISION_REQUIRED')),
reference_code text not null,
statement text not null,
content_hash text not null,
created_at timestamptz not null default now(),
unique (hypothesis_id, side, reference_code, content_hash)
);
create table if not exists governance.model_activation_decision (
activation_decision_id uuid primary key,
scope_key text not null,
candidate_model_version text not null,
promotion_review_id uuid not null references governance.model_promotion_review(review_id),
decision text not null check (decision in ('KEEP_CURRENT_CHAMPION','ACTIVATE_FOR_SHADOW','ACTIVATE_FOR_PILOT','REJECT','EXPIRE')),
effective_at timestamptz null,
rollback_model_version text not null,
maker_id text not null,
checker_id text not null,
actor_type text not null check (actor_type = 'HUMAN_CHANGE_APPROVAL'),
change_ticket text not null,
evidence_bundle_hash text not null,
content_hash text not null unique,
decided_at timestamptz not null,
check (maker_id <> checker_id),
check (decision not in ('ACTIVATE_FOR_SHADOW','ACTIVATE_FOR_PILOT') or effective_at is not null)
);
-- Immutable evidence. The cycle aggregate itself remains mutable only through optimistic application logic;
-- every transition is captured here and cannot be edited or deleted.
drop trigger if exists model_feedback_transition_append_only on evaluation.model_feedback_transition;
create trigger model_feedback_transition_append_only
before update or delete on evaluation.model_feedback_transition
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_hypothesis_evidence_append_only on governance.model_hypothesis_evidence;
create trigger model_hypothesis_evidence_append_only
before update or delete on governance.model_hypothesis_evidence
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists model_activation_decision_append_only on governance.model_activation_decision;
create trigger model_activation_decision_append_only
before update or delete on governance.model_activation_decision
for each row execute function building_blocks.prevent_append_only_change();
comment on table governance.model_activation_decision is
'Human-only activation decision. Scheduler, Hangfire worker and proposal jobs must not insert into this table.';
-- Integrity audit is disabled until cycle aging, ownership and alert contracts are approved.
insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner,
calendar_id, due_policy, dependency_json, catch_up_policy, max_catch_up)
values
('e4100000-0000-4000-8000-000000000039','J39','FeedbackCycleIntegrityAudit','GLOBAL','DAILY','EVALUATION_ONLY','q-control',1,false,now()+interval '1 day',interval '1 day','Compliance/QA','Quant/SRE','GLOBAL_UTC','FIXED_CADENCE','["FEEDBACK_CYCLE_CONTRACT_APPROVED","AGING_POLICY_APPROVED"]','LATEST_ONLY',1)
on conflict (operation_code, scope_key, schedule_version) do nothing;
@@ -0,0 +1,112 @@
-- v15.0 execution-completeness delta.
-- Evidence evaluation/proposal automation only. Automatic model activation, client publication,
-- automatic order submission and KIS submission remain forbidden.
alter table evaluation.model_operation_schedule
add column if not exists dispatch_revision integer not null default 0 check (dispatch_revision >= 0),
add column if not exists anchor_at timestamptz null,
add column if not exists timezone_id text not null default 'UTC',
add column if not exists last_completed_at timestamptz null,
add column if not exists last_hold_code text null;
update evaluation.model_operation_schedule
set anchor_at = coalesce(anchor_at, next_due_at)
where anchor_at is null;
alter table evaluation.model_operation_request
add column if not exists execution_revision integer not null default 1 check (execution_revision > 0),
add column if not exists last_heartbeat_at timestamptz null,
add column if not exists hold_until timestamptz null,
add column if not exists status_reason_code text null,
add column if not exists scheduled_for timestamptz null;
create table if not exists evaluation.prediction_evaluation_window (
window_request_id uuid primary key,
prediction_evidence_id uuid not null,
scope_key text not null,
calendar_id text not null,
prediction_session date not null,
window_trading_days integer not null check (window_trading_days in (1,5,20,63,126,252)),
due_session date not null,
status text not null check (status in ('PLANNED','MATURED','EVALUATED','BUSINESS_HOLD','QUARANTINED')),
dataset_id text not null,
model_version text not null,
metric_definition_set_hash text not null,
content_hash text not null unique,
created_at timestamptz not null,
matured_at timestamptz null,
evaluated_at timestamptz null,
check (due_session >= prediction_session),
unique (prediction_evidence_id, window_trading_days, metric_definition_set_hash)
);
create index if not exists ix_prediction_evaluation_window_due
on evaluation.prediction_evaluation_window (due_session, status, scope_key)
where status in ('PLANNED','BUSINESS_HOLD');
create table if not exists evaluation.metric_cohort_definition (
cohort_code text not null,
definition_version integer not null check (definition_version > 0),
scope_expression text not null,
inclusion_expression text not null,
exclusion_expression text not null,
minimum_sample_size integer not null check (minimum_sample_size >= 0),
effective_from timestamptz not null,
effective_to timestamptz null,
status text not null check (status in ('PROPOSED','APPROVED','RETIRED')),
content_hash text not null unique,
approved_by text null,
approved_at timestamptz null,
primary key (cohort_code, definition_version),
check (effective_to is null or effective_to > effective_from),
check (status <> 'APPROVED' or (approved_by is not null and approved_at is not null))
);
create table if not exists governance.ui_contract_release (
ui_contract_release_id uuid primary key,
contract_version text not null,
provider_id text not null,
provider_version text not null,
capability_hash text not null,
screen_template_hash text not null,
accessibility_evidence_hash text not null,
visual_regression_hash text null,
performance_evidence_hash text null,
status text not null check (status in ('PROPOSED','APPROVED','RETIRED')),
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null default now(),
content_hash text not null unique,
unique (contract_version, provider_id, provider_version),
check (status <> 'APPROVED' or (approved_by is not null and approved_at is not null))
);
-- Evaluation windows, cohort definitions and UI contract approvals are immutable evidence.
drop trigger if exists prediction_evaluation_window_append_only on evaluation.prediction_evaluation_window;
create trigger prediction_evaluation_window_append_only
before update or delete on evaluation.prediction_evaluation_window
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists metric_cohort_definition_append_only on evaluation.metric_cohort_definition;
create trigger metric_cohort_definition_append_only
before update or delete on evaluation.metric_cohort_definition
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists ui_contract_release_append_only on governance.ui_contract_release;
create trigger ui_contract_release_append_only
before update or delete on governance.ui_contract_release
for each row execute function building_blocks.prevent_append_only_change();
comment on table evaluation.prediction_evaluation_window is
'Immutable 1/5/20/63/126/252 trading-session maturity plan. Revisions create new evidence rows.';
comment on table governance.ui_contract_release is
'Approved normalized UI contract/provider evidence. It does not authorize feature behavior or investment decisions.';
-- Integrity audit remains disabled until approved calendar/cohort definitions and alert runbook exist.
insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner,
calendar_id, due_policy, dependency_json, catch_up_policy, max_catch_up, anchor_at, timezone_id)
values
('e4100000-0000-4000-8000-000000000040','J40','EvaluationWindowIntegrityAudit','GLOBAL','DAILY','EVALUATION_ONLY','q-control',1,false,now()+interval '1 day',interval '1 day','Quant/QA','Data/SRE','GLOBAL_UTC','FIXED_CADENCE','["TRADING_CALENDAR_APPROVED","METRIC_COHORT_APPROVED"]','LATEST_ONLY',1,now()+interval '1 day','UTC')
on conflict (operation_code, scope_key, schedule_version) do nothing;
@@ -0,0 +1,87 @@
-- v16.0 reference implementation closure.
-- Evaluation/proposal/audit only. Automatic model activation, customer publication,
-- automatic order submission and KIS submission remain forbidden.
create table if not exists evaluation.model_operation_lease (
operation_code text not null,
scope_key text not null,
fencing_token bigint not null check (fencing_token > 0),
lease_owner text not null,
acquired_at timestamptz not null,
expires_at timestamptz not null,
heartbeat_at timestamptz not null,
dispatch_revision integer not null check (dispatch_revision >= 0),
primary key (operation_code, scope_key),
check (expires_at > acquired_at),
check (heartbeat_at >= acquired_at)
);
create table if not exists evaluation.model_evaluation_reconciliation (
reconciliation_id uuid primary key,
prediction_evidence_id uuid not null,
window_trading_days integer not null check (window_trading_days in (1,5,20,63,126,252)),
action text not null check (action in ('NONE','PLAN_MISSING','QUARANTINE_DUPLICATE','BUSINESS_HOLD_LATE','RECALCULATE_REVISION')),
metric_definition_set_hash text not null,
cohort_definition_hash text not null,
dataset_id text not null,
source_revision_hash text not null,
reason_code text not null,
content_hash text not null unique,
created_at timestamptz not null,
unique (prediction_evidence_id, window_trading_days, content_hash)
);
create table if not exists building_blocks.projection_rebuild_request (
rebuild_request_id uuid primary key,
projection_name text not null,
requested_version integer not null check (requested_version > 0),
source_watermark text not null,
requested_by text not null,
reason_code text not null,
status text not null check (status in ('REQUESTED','RUNNING','SUCCEEDED','FAILED','QUARANTINED')),
before_hash text null,
after_hash text null,
requested_at timestamptz not null,
completed_at timestamptz null,
content_hash text not null unique,
check (completed_at is null or completed_at >= requested_at)
);
create table if not exists governance.ui_adapter_compatibility_evidence (
compatibility_evidence_id uuid primary key,
contract_version text not null,
provider_id text not null,
provider_version text not null,
capability_hash text not null,
contract_test_hash text not null,
accessibility_test_hash text not null,
visual_test_hash text null,
performance_test_hash text null,
rollback_test_hash text null,
status text not null check (status in ('PROPOSED','APPROVED','REJECTED','RETIRED')),
approved_by text null,
approved_at timestamptz null,
created_at timestamptz not null,
content_hash text not null unique,
check (status <> 'APPROVED' or (approved_by is not null and approved_at is not null))
);
drop trigger if exists model_evaluation_reconciliation_append_only on evaluation.model_evaluation_reconciliation;
create trigger model_evaluation_reconciliation_append_only before update or delete on evaluation.model_evaluation_reconciliation
for each row execute function building_blocks.prevent_append_only_change();
drop trigger if exists ui_adapter_compatibility_evidence_append_only on governance.ui_adapter_compatibility_evidence;
create trigger ui_adapter_compatibility_evidence_append_only before update or delete on governance.ui_adapter_compatibility_evidence
for each row execute function building_blocks.prevent_append_only_change();
insert into evaluation.model_operation_schedule
(schedule_id, operation_code, operation_name, scope_key, cadence, automation_mode, queue_name,
schedule_version, enabled, next_due_at, max_lag, primary_owner, secondary_owner,
calendar_id, due_policy, dependency_json, catch_up_policy, max_catch_up, anchor_at, timezone_id)
values
('e4100000-0000-4000-8000-000000000041','J41','SchedulerLeaseIntegrityAudit','GLOBAL','DAILY','EVALUATION_ONLY','q-control',1,false,now()+interval '1 day',interval '1 day','SRE/QA','BE/DBA','GLOBAL_UTC','FIXED_CADENCE','["LEASE_CONTRACT_APPROVED","ALERT_RUNBOOK_APPROVED"]','LATEST_ONLY',1,now()+interval '1 day','UTC'),
('e4100000-0000-4000-8000-000000000042','J42','ModelEvaluationReconciliation','GLOBAL','DAILY','EVALUATION_ONLY','q-evaluation',1,false,now()+interval '1 day',interval '1 day','Quant/QA','Data/Risk','GLOBAL_UTC','FIXED_CADENCE','["TRADING_CALENDAR_APPROVED","METRIC_COHORT_APPROVED","SOURCE_REVISION_INDEX_READY"]','LATEST_ONLY',1,now()+interval '1 day','UTC')
on conflict (operation_code, scope_key, schedule_version) do nothing;
comment on table evaluation.model_operation_lease is 'Lease fencing prevents stale workers from advancing schedules or duplicating model evaluation side effects.';
comment on table evaluation.model_evaluation_reconciliation is 'Append-only evaluation repair plan. It never activates a model or submits an order.';