internal/infra/pg/factsupportrecovery.go
internal/infra/pg · 132 lines · 2 declarations · source
Declarations
func repairFactSupportTx
func repairFactSupportTx(ctx context.Context, tx pgx.Tx, schema Schema, scope, id string) (bool, error)
Repair support only after ordinary missing-fact recovery declined the row. Lock the retained fact and its receipt so correction cannot change the state between validation and registration. A missing component is recoverable; an existing conflicting component is an integrity refusal, never an invitation to rewrite a caller-visible record or guess at authoritative source bytes.
const factSupportRegistrationsSQL
const factSupportRegistrationsSQL = `
SELECT r.source_observation_id,r.scope,'fact'::text AS projection_kind,r.fact_id::text AS projection_id,o.data_subject_id,r.pipeline_version
FROM {schema}.fact_receipt r JOIN {schema}.observation o ON o.scope=r.scope AND o.observation_id=r.source_observation_id
WHERE r.scope=$1 AND r.fact_id=$2::uuid
UNION
SELECT r.source_observation_id,r.scope,'entity',endpoint.id::text,o.data_subject_id,r.pipeline_version
FROM {schema}.fact_receipt r JOIN {schema}.fact f ON f.scope=r.scope AND f.fact_id=r.fact_id
JOIN {schema}.observation o ON o.scope=r.scope AND o.observation_id=r.source_observation_id
CROSS JOIN LATERAL unnest(ARRAY[f.subject_entity_id,f.object_entity_id]) endpoint(id)
WHERE r.scope=$1 AND r.fact_id=$2::uuid AND endpoint.id IS NOT NULL
UNION
SELECT r.source_observation_id,r.scope,'fact_history',h.history_id::text,o.data_subject_id,r.pipeline_version
FROM {schema}.fact_receipt r JOIN {schema}.fact_receipt_history h ON h.scope=r.scope AND h.fact_id=r.fact_id
JOIN {schema}.observation o ON o.scope=r.scope AND o.observation_id=r.source_observation_id
WHERE r.scope=$1 AND r.fact_id=$2::uuid
UNION
SELECT h.source_observation_id,h.scope,'fact_history',h.history_id::text,o.data_subject_id,r.pipeline_version
FROM {schema}.fact_receipt r JOIN {schema}.fact_receipt_history h ON h.scope=r.scope AND h.fact_id=r.fact_id
JOIN {schema}.observation o ON o.scope=h.scope AND o.observation_id=h.source_observation_id
WHERE r.scope=$1 AND r.fact_id=$2::uuid`
Expected registrations use the live retained endpoints and the source-owned history. A temporal transition belongs to both original and causal sources; rebuilding just one registration would make erasure by the other subject silently leave their historical contribution behind.