40-clients/ucepsa/edge-oee-demo/ops/validate_canonical_context_arbitration_v038.sql
2026-07-20 13:40:38 +02:00

269 lines
6.5 KiB
SQL

\pset pager off
\echo '=== 1. Objetos v0.3.8 ==='
SELECT
to_regclass(
'mv_loss_intelligence.context_arbitration_source_policies'
) AS policy_table,
to_regclass(
'mv_reports_ucepsa_prod.li_canonical_context_candidates_v1'
) AS candidates_view,
to_regclass(
'mv_reports_ucepsa_prod.li_canonical_context_segments_v1'
) AS segments_view,
to_regclass(
'mv_reports_ucepsa_prod.li_context_arbitration_conflicts_v1'
) AS conflicts_view,
to_regclass(
'mv_reports_ucepsa_prod.li_machine_canonical_context_live_v1'
) AS live_view,
to_regclass(
'mv_reports_ucepsa_prod.li_canonical_context_coverage_v1'
) AS coverage_view,
to_regclass(
'mv_reports_ucepsa_prod.li_stop_canonical_context_slices_v1'
) AS stop_slices_view,
to_regclass(
'mv_reports_ucepsa_prod.li_stop_canonical_context_shadow_v1'
) AS stop_shadow_view,
to_regclass(
'mv_reports_ucepsa_prod.li_canonical_context_diagnostics_v1'
) AS diagnostics_view;
\echo '=== 2. Política de fuentes ==='
SELECT
source_type,
candidate_role,
source_rank,
productive_context,
active
FROM
mv_loss_intelligence
.context_arbitration_source_policies
WHERE tenant = 'ucepsa'
AND site = 'ucepsa_onpremise'
AND policy_code =
'CUTTER_CANONICAL_CONTEXT_V1'
ORDER BY source_rank;
\echo '=== 3. Claves de candidato sin colisiones ==='
WITH duplicated AS (
SELECT
tenant,
site,
context_key,
COUNT(*) AS n
FROM
mv_reports_ucepsa_prod
.li_canonical_context_candidates_v1
GROUP BY
tenant,
site,
context_key
HAVING COUNT(*) > 1
)
SELECT COUNT(*) AS candidate_key_collisions
FROM duplicated;
\echo '=== 4. Invariantes temporales de segmentos ==='
SELECT
COUNT(*) FILTER (
WHERE segment_to <= segment_from
) AS invalid_segment_intervals,
COUNT(*) FILTER (
WHERE segment_duration_s < 0
) AS negative_segment_durations
FROM
mv_reports_ucepsa_prod
.li_canonical_context_segments_v1;
\echo '=== 5. Semántica canónica ==='
SELECT
COUNT(*) FILTER (
WHERE authoritative_candidate_count = 1
AND canonical_context_key IS NULL
) AS one_candidate_without_canonical_key,
COUNT(*) FILTER (
WHERE authoritative_candidate_count <> 1
AND canonical_context_key IS NOT NULL
) AS ambiguous_with_canonical_key,
COUNT(*) FILTER (
WHERE canonical_context_source IN (
'ODOO_ORDER_CONTEXT',
'INFERRED_SHADOW'
)
) AS supporting_promoted_to_canonical,
COUNT(*) FILTER (
WHERE canonical_context_status =
'CONTEXT_CONFLICT'
AND NOT review_required
) AS conflict_without_review
FROM
mv_reports_ucepsa_prod
.li_canonical_context_segments_v1;
\echo '=== 6. Una fila viva por máquina ==='
SELECT
COUNT(*) AS live_machine_rows,
COUNT(
DISTINCT machine_id
) AS distinct_live_machines,
COUNT(*) FILTER (
WHERE official_ledger_eligible
) AS official_live_rows
FROM
mv_reports_ucepsa_prod
.li_machine_canonical_context_live_v1;
\echo '=== 7. Estado vivo actual ==='
SELECT
machine_id,
telemetry_fresh,
machine_running,
published_production_order,
published_workorder_id,
authoritative_candidate_count,
authoritative_context_sources,
canonical_context_key,
canonical_context_source,
canonical_context_status,
canonical_order_ref,
canonical_odoo_workorder_id,
operator_name,
operator_candidate_name,
order_alignment_status,
canonical_health_status,
recommended_action,
official_ledger_eligible
FROM
mv_reports_ucepsa_prod
.li_machine_canonical_context_live_v1
ORDER BY machine_id;
\echo '=== 8. Candidatos históricos conocidos ==='
SELECT
source_type,
candidate_role,
context_key,
machine_id,
order_ref,
odoo_workorder_id,
context_from,
context_to,
context_record_status,
authorization_status,
operator_name,
operator_candidate_name,
official_eligible
FROM
mv_reports_ucepsa_prod
.li_canonical_context_candidates_v1
WHERE odoo_workorder_id IN (
87,
810,
340
)
OR production_context_session_id = 1
ORDER BY
context_from,
source_rank,
context_key;
\echo '=== 9. Conflictos de arbitraje ==='
SELECT *
FROM
mv_reports_ucepsa_prod
.li_context_arbitration_conflicts_v1
WHERE segment_to >=
now() - interval '24 hours'
ORDER BY segment_from DESC
LIMIT 30;
\echo '=== 10. Duración de slices no supera el paro raw ==='
WITH totals AS (
SELECT
source_stop_id,
MAX(raw_duration_s)
AS raw_duration_s,
SUM(segment_duration_s)
AS sliced_duration_s
FROM
mv_reports_ucepsa_prod
.li_stop_canonical_context_slices_v1
GROUP BY source_stop_id
)
SELECT COUNT(*) AS stop_duration_overflow_count
FROM totals
WHERE sliced_duration_s >
raw_duration_s + 1::numeric;
\echo '=== 11. Paros abiertos y contextos no productivos no elegibles ==='
SELECT
COUNT(*) FILTER (
WHERE source_status = 'OPEN'
AND technically_eligible
) AS open_stops_marked_eligible,
COUNT(*) FILTER (
WHERE NOT canonical_productive_context
AND technically_eligible
) AS nonproductive_stops_marked_eligible,
COUNT(*) FILTER (
WHERE authoritative_candidate_count <> 1
AND technically_eligible
) AS ambiguous_stops_marked_eligible
FROM
mv_reports_ucepsa_prod
.li_stop_canonical_context_shadow_v1;
\echo '=== 12. Nada oficial ==='
SELECT
(
SELECT COUNT(*)
FROM
mv_reports_ucepsa_prod
.li_stop_canonical_context_shadow_v1
WHERE official_ledger_eligible
) AS official_canonical_stop_rows,
(
SELECT COUNT(*)
FROM
mv_reports_ucepsa_prod
.li_canonical_context_segments_v1
WHERE official_ledger_eligible
) AS official_canonical_segment_rows,
(
SELECT COUNT(*)
FROM
mv_reports_ucepsa_prod
.li_operator_stop_queue_v2
) AS official_operator_queue_rows;
\echo '=== 13. Diagnóstico 24 horas ==='
SELECT *
FROM
mv_reports_ucepsa_prod
.li_canonical_context_diagnostics_v1;
\echo '=== 14. Cobertura canónica 30 días ==='
SELECT *
FROM
mv_reports_ucepsa_prod
.li_canonical_context_coverage_v1
ORDER BY
machine_id,
hours DESC;