3b76070394
✅ Database Setup: - Created PostgreSQL kartselldb with kartsell user - SSH port forward established (localhost:5432 → 178.104.200.7:5432) ✅ DbMigrator Fixes: - Fixed migration path discovery (AppContext.BaseDirectory fallback) - Added empty variable dictionary to suppress DbUp preprocessing - Fixed PostgreSQL dollar quoting conflict ($policy$ → $$) ✅ Migration Results: - All 21 migrations executed successfully - Schema versions journal created and tracked - 21 scripts processed in order, no rollback needed Status: FRESH DATABASE DEPLOYMENT SUCCESSFUL - kartselldb fully initialized with v16 schema - Ready for application startup Next: Deploy application and run integration tests Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
150 lines
5.3 KiB
SQL
150 lines
5.3 KiB
SQL
-- 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', $$
|
|
{
|
|
"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"
|
|
}
|
|
$$::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();
|