Files
html/api/v84-linkedin-archi-live-score.php
2026-04-20 04:43:30 +02:00

119 lines
5.1 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// V84 LinkedIn × Archi score — computed live (not hardcoded)
// Replaces hardcoded audit_score: 4.8 with real calculation from 10 KPIs
header("Content-Type: application/json");
$base_kpi = @json_decode(@file_get_contents("http://127.0.0.1/api/linkedin-alignment-kpi.php"), true);
if (!$base_kpi) { echo json_encode(['error'=>'base KPI fetch failed']); exit; }
$kpis = $base_kpi['kpis'] ?? [];
// Score weights per KPI status
function score_kpi($kpi) {
$s = strtoupper($kpi['status'] ?? 'TBD');
switch ($s) {
case 'OK': return 1.0;
case 'BELOW': return 0.3;
case 'SKEWED': return 0.4;
case 'CRITICAL': return 0.0;
case 'PENDING': return 0.5;
case 'TBD': return 0.5;
default: return 0.3;
}
}
$total_score = 0;
$max_possible = count($kpis); // 1 point per KPI
$breakdown = [];
$levers = [];
foreach ($kpis as $key => $kpi) {
$pts = score_kpi($kpi);
$total_score += $pts;
$status = $kpi['status'] ?? 'TBD';
$value = $kpi['value'] ?? 0;
$target = $kpi['target'] ?? $kpi['target_range'][1] ?? '—';
$breakdown[$key] = [
'status' => $status,
'points' => $pts,
'max_points' => 1.0,
'value' => $value,
'target' => $target,
];
if ($pts < 1.0) {
$potential_gain = 1.0 - $pts;
$levers[] = [
'kpi' => $key,
'current_status' => $status,
'potential_gain' => round($potential_gain, 2),
'action' => get_lever_action($key, $kpi),
'priority' => $potential_gain >= 0.7 ? 'HIGH' : ($potential_gain >= 0.4 ? 'MEDIUM' : 'LOW'),
];
}
}
function get_lever_action($key, $kpi) {
switch ($key) {
case 'risky_claims':
$posts = $kpi['posts'] ?? [];
return 'OWNER: rewrite ' . count($posts) . ' posts removing claims "+500%" / "52 domaines" / "launch in days" — specifically: ' . implode(' | ', array_slice($posts, 0, 3));
case 'tagline_compliance':
return 'OWNER: Deploy V1 tagline consistent across corp + LS accounts + update LinkedIn headline';
case 'avg_reach_30d':
return 'OWNER: (1) Post more regularly 3-5x/week (2) Use native video+docs formats (3) Engage first 1h (4) Target: 800+ views/post';
case 'posts_with_metric':
return 'OWNER: Add concrete numbers to each post (client count, ROI%, hours saved, clients onboarded) — chiffres-chocs rule';
case 'unique_proofs_cited':
return 'OWNER: Track /live-status landing hits + cite 15+ unique proofs/month (MRR, clients, ARR, NPS live)';
case 'linkedin_to_demo':
return 'OWNER: Wire landing /demo tracking → target 30 discovery calls/month from LinkedIn CTAs';
case 'named_cases_month':
return 'OWNER: Publish 2+ named case studies/month (Ethica, Vistex, Huawei) with client approval';
case 'account_parity':
return 'Balance corp vs LS post ratio between 0.8-1.2';
case 'public_services_up':
return 'Keep public services >80% uptime — check realtime-status';
case 'engagement_rate_30d':
return 'Maintain current 4.02% (already OK)';
default:
return 'Review KPI source';
}
}
$score_live = round($total_score / $max_possible * 10, 1); // normalize to /10
$score_hardcoded = $base_kpi['audit_score'] ?? 4.8;
// Max potential score = if all BELOW/CRITICAL become OK
$max_potential_score = 0;
foreach ($kpis as $key => $kpi) {
$status = $kpi['status'] ?? 'TBD';
if (in_array($status, ['OK'])) $max_potential_score += 1.0;
else $max_potential_score += 0.95; // realistic achievable after owner action
}
$max_potential_normalized = round($max_potential_score / $max_possible * 10, 1);
// Sort levers by priority
usort($levers, function($a,$b){ return $b['potential_gain'] <=> $a['potential_gain']; });
echo json_encode([
'v' => 'V84-linkedin-archi-score-live-computed',
'ts' => date('c'),
'score_live_computed' => $score_live,
'score_hardcoded_outdated' => $score_hardcoded,
'score_max' => 10.0,
'max_potential_after_owner_actions' => $max_potential_normalized,
'potential_gain' => round($max_potential_normalized - $score_live, 1),
'total_kpis' => $max_possible,
'kpis_ok' => count(array_filter($breakdown, fn($k) => $k['status']==='OK')),
'kpis_critical' => count(array_filter($breakdown, fn($k) => $k['status']==='CRITICAL')),
'kpis_below' => count(array_filter($breakdown, fn($k) => $k['status']==='BELOW')),
'breakdown' => $breakdown,
'levers_prioritized' => $levers,
'owner_action_plan' => [
'P0_immediate' => array_values(array_filter($levers, fn($l) => $l['priority']==='HIGH')),
'P1_week' => array_values(array_filter($levers, fn($l) => $l['priority']==='MEDIUM')),
'P2_month' => array_values(array_filter($levers, fn($l) => $l['priority']==='LOW')),
],
'doctrine_4_honest' => 'score 4.8 was HARDCODED in linkedin-alignment-kpi.php line 86, now computed live from 10 KPIs status weights. Max theoretical 9.5+ reachable after owner rewrites 3 risky posts + deploys tagline V1 + tracks reach metrics',
], JSON_PRETTY_PRINT);