% Flagship example: operational incident diagnosis and response.
% The topology, incident observations, telemetry, and runbook are RDF data.
% Prolog correlates evidence, traverses service dependencies, and recommends a
% bounded mitigation with an inspectable evidence chain.

%% goal: root_cause(X0, X1, X2)
%% goal: impacted_service(X0, X1)
%% goal: recommended_action(X0, X1)
%% goal: evidence_chain(X0, X1)

v(depends_on,iri('https://example.org/vocab/dependsOn')).
v(symptom,iri('https://example.org/vocab/symptom')).
v(observed_on,iri('https://example.org/vocab/observedOn')).
v(status,iri('https://example.org/vocab/status')).
v(disk_usage,iri('https://example.org/vocab/diskUsagePercent')).
v(error_rate,iri('https://example.org/vocab/errorRatePercent')).
v(when_cause,iri('https://example.org/vocab/whenCause')).
v(action,iri('https://example.org/vocab/action')).

g(topology,iri('https://example.org/operations/graph/topology')).
g(telemetry,iri('https://example.org/operations/graph/telemetry')).
g(incident,iri('https://example.org/operations/graph/incident')).
g(runbook,iri('https://example.org/operations/graph/runbook')).

resource(inc900,iri('https://example.org/operations/incident/inc-900')).
resource(storefront,iri('https://example.org/operations/service/storefront')).
resource(mobile_app,iri('https://example.org/operations/service/mobile-app')).
resource(checkout_api,iri('https://example.org/operations/service/checkout-api')).
resource(payment_api,iri('https://example.org/operations/service/payment-api')).
resource(auth_service,iri('https://example.org/operations/service/auth-service')).
resource(primary_db,iri('https://example.org/operations/db/primary')).
resource(replica_db,iri('https://example.org/operations/db/replica')).

integer_literal(literal(Text,datatype('http://www.w3.org/2001/XMLSchema#integer')),N):-atom_chars(Text,Cs),number_chars(N,Cs).

depends(A,B):-resource(A,RA),resource(B,RB),v(depends_on,P),g(topology,G),rdf(RA,P,RB,G).
transitively_depends(A,B):-depends(A,B).
transitively_depends(A,B):-depends(A,C),transitively_depends(C,B).

telemetry(Resource,Key,Value):-resource(Resource,R),v(Key,P),g(telemetry,G),rdf(R,P,Value,G).
incident_fact(Key,Value):-resource(inc900,I),v(Key,P),g(incident,G),rdf(I,P,Value,G).

root_cause(inc900,primary_db,disk_full):-
 incident_fact(symptom,iri('https://example.org/operations/symptom/db-timeout')),
 telemetry(primary_db,status,iri('https://example.org/operations/state/unhealthy')),
 telemetry(primary_db,disk_usage,L),integer_literal(L,100),
 telemetry(payment_api,error_rate,E),integer_literal(E,Rate),Rate >= 50,
 telemetry(auth_service,status,iri('https://example.org/operations/state/healthy')).

impacted_service(inc900,primary_db):-root_cause(inc900,primary_db,_).
impacted_service(inc900,Service):-root_cause(inc900,primary_db,_),transitively_depends(Service,primary_db).

cause_iri(disk_full,iri('https://example.org/operations/cause/disk-full')).
action_iri(failover_to_replica,iri('https://example.org/operations/action/failover-to-replica')).
runbook_action(Cause,Action):-g(runbook,G),v(when_cause,PC),v(action,PA),cause_iri(Cause,C),action_iri(Action,A),rdf(Rule,PC,C,G),rdf(Rule,PA,A,G).

recommended_action(inc900,failover(primary_db,replica_db)):-
 root_cause(inc900,primary_db,disk_full),runbook_action(disk_full,failover_to_replica),telemetry(replica_db,status,iri('https://example.org/operations/state/healthy')).

evidence_chain(inc900,[payment_api_db_timeout,primary_db_unhealthy,primary_db_disk_100_percent,auth_service_healthy,replica_db_healthy]):-recommended_action(inc900,_).

result_rdf(I,iri('https://example.org/vocab/rootCause'),C,iri('https://example.org/operations/graph/derived')):-root_cause(inc900,primary_db,disk_full),resource(inc900,I),resource(primary_db,C).
result_rdf(I,iri('https://example.org/vocab/recommendedAction'),ActionIri,iri('https://example.org/operations/graph/derived')):-recommended_action(inc900,_),runbook_action(disk_full,failover_to_replica),action_iri(failover_to_replica,ActionIri),resource(inc900,I).
result_rdf(I,iri('https://example.org/vocab/impacts'),S,iri('https://example.org/operations/graph/derived')):-impacted_service(inc900,Service),resource(inc900,I),resource(Service,S).

write_results:-result_rdf(S,P,O,G),write_term(rdf(S,P,O,G),[quoted(true)]),write('.'),nl,fail.
write_results.
:- set_prolog_flag(unknown, fail).
