63 lines
3.7 KiB
PL/PgSQL
63 lines
3.7 KiB
PL/PgSQL
-- Durable persistent-forward charge; no execution authority is issued.
|
|
-- Reuses the accepted B2.a immutable-parent charging rule, narrowed to ONE
|
|
-- forward charge. Existing 0040 two-slot reservations/0031 remain untouched.
|
|
-- This SQL cannot authenticate a binding or grant execution authority.
|
|
BEGIN;
|
|
DO $$ BEGIN
|
|
IF to_regclass('public.mcp_routing_forward_charges') IS NOT NULL
|
|
THEN RAISE EXCEPTION 'unmarked forward charge storage requires explicit reconciliation'; END IF;
|
|
END $$;
|
|
CREATE TABLE public.mcp_routing_forward_charges (
|
|
-- Logical historical identities, intentionally NOT lifetime FKs. INSERT is
|
|
-- checked against the actual current source below; later source/profile
|
|
-- retention cannot erase this charge or be blocked forever by old charges.
|
|
source_operation_id uuid PRIMARY KEY,
|
|
source_plan_id uuid NOT NULL,
|
|
source_step_index integer NOT NULL CHECK(source_step_index=0),
|
|
profile_id uuid NOT NULL,
|
|
connection_id uuid NOT NULL,
|
|
charge_units integer NOT NULL DEFAULT 1 CHECK(charge_units=1),
|
|
binding_sealed text NOT NULL CHECK(octet_length(binding_sealed) BETWEEN 1 AND 262144),
|
|
binding_proof text NOT NULL CHECK(binding_proof ~ '^[a-f0-9]{64}$'),
|
|
created_at timestamptz NOT NULL
|
|
);
|
|
CREATE INDEX mcp_routing_forward_charges_window
|
|
ON public.mcp_routing_forward_charges(profile_id,created_at);
|
|
CREATE INDEX mcp_routing_forward_charges_retention
|
|
ON public.mcp_routing_forward_charges(created_at,source_operation_id);
|
|
-- The immutable parent IS the charged unit. No mutable status/child can drop it
|
|
-- from the hourly projection after reject/unknown, human save or restart.
|
|
CREATE FUNCTION public.mcp_routing_forward_charge_source() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
IF NOT EXISTS(
|
|
SELECT 1 FROM public.mcp_operations o
|
|
JOIN public.mcp_plans p ON p.id=o.plan_id AND p.connection_id=o.connection_id
|
|
JOIN public.mcp_routing_profiles r ON r.id=NEW.profile_id AND r.connection_id=o.connection_id
|
|
WHERE o.id=NEW.source_operation_id AND p.id=NEW.source_plan_id
|
|
AND o.connection_id=NEW.connection_id AND o.state='pending' AND p.state='executing'
|
|
AND p.operation_id='routing.community.switch' AND p.operation_version=7
|
|
) THEN RAISE EXCEPTION 'forward charge differs from actual pending admission source'; END IF;
|
|
RETURN NEW;
|
|
END $$;
|
|
CREATE TRIGGER mcp_routing_forward_charge_source BEFORE INSERT ON public.mcp_routing_forward_charges
|
|
FOR EACH ROW EXECUTE FUNCTION public.mcp_routing_forward_charge_source();
|
|
CREATE FUNCTION public.mcp_routing_forward_charge_immutable() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
DECLARE retention integer;
|
|
BEGIN
|
|
IF TG_OP<>'DELETE' THEN RAISE EXCEPTION 'immutable forward charge; rewrite/refund forbidden'; END IF;
|
|
SELECT requests_retention_days INTO retention FROM public.mcp_settings WHERE id=1 FOR SHARE;
|
|
IF retention IS NULL OR retention NOT BETWEEN 1 AND 365
|
|
OR OLD.created_at>clock_timestamp()-interval '1 hour'
|
|
OR OLD.created_at>=clock_timestamp()-make_interval(days=>retention)
|
|
OR EXISTS(SELECT 1 FROM public.mcp_operations WHERE id=OLD.source_operation_id AND state IN('pending','running'))
|
|
THEN RAISE EXCEPTION 'forward charge is still retained or unresolved'; END IF;
|
|
RETURN OLD;
|
|
END $$;
|
|
CREATE TRIGGER mcp_routing_forward_charge_immutable BEFORE UPDATE OR DELETE ON public.mcp_routing_forward_charges
|
|
FOR EACH ROW EXECUTE FUNCTION public.mcp_routing_forward_charge_immutable();
|
|
CREATE TRIGGER mcp_routing_forward_charge_no_truncate BEFORE TRUNCATE ON public.mcp_routing_forward_charges
|
|
FOR EACH STATEMENT EXECUTE FUNCTION public.mcp_routing_forward_charge_immutable();
|
|
-- DDL and exact file marker commit atomically. No SECURITY DEFINER or grants.
|
|
INSERT INTO public.schema_migrations (id) VALUES ('0043_mcp_routing_forward_charges') ON CONFLICT (id) DO NOTHING;
|
|
COMMIT;
|