| 1 |
<?php |
| 2 |
|
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; |
| 5 |
} |
| 6 |
|
| 7 |
/** |
| 8 |
* Renders reconstructed canary-receipt evidence into the support payload. |
| 9 |
* |
| 10 |
* The diagnostic evidence class owns journal correlation and interpretation. |
| 11 |
* This class owns only the presentation boundary: a stable grep key, a compact |
| 12 |
* human header, and whole-record reduction that never cuts JSON mid-document. |
| 13 |
*/ |
| 14 |
final class ABJ_404_Solution_CanaryReceiptSupportSection { |
| 15 |
|
| 16 |
/** Reallocated from the generic sanitized log tail and pinned by the budget test. */ |
| 17 |
const MAX_CANARY_RECEIPT_INTERPRETATION_BYTES = 4096; |
| 18 |
|
| 19 |
/** Stable payload key for receipt-derived interpretation. */ |
| 20 |
const INTERPRETATION_KEY = 'abj404_canary_receipt_interpretation'; |
| 21 |
|
| 22 |
public static function compose(string $sessionId): string { |
| 23 |
if (!class_exists('ABJ_404_Solution_CanaryReceiptEvidence')) { |
| 24 |
return 'Canary receipt interpretation unavailable: ABJ_404_Solution_CanaryReceiptEvidence' |
| 25 |
. ' could not be loaded on this install.'; |
| 26 |
} |
| 27 |
try { |
| 28 |
return self::render(ABJ_404_Solution_CanaryReceiptEvidence::forSession($sessionId)); |
| 29 |
} catch (Throwable $e) { |
| 30 |
return 'Canary receipt interpretation could not be computed: ' |
| 31 |
. substr($e->getMessage(), 0, 200); |
| 32 |
} |
| 33 |
} |
| 34 |
|
| 35 |
/** @param array<string, mixed> $record */ |
| 36 |
private static function render(array $record): string { |
| 37 |
$status = self::textField($record, 'status'); |
| 38 |
$header = 'Canary interpretation reconstructed from checkpoint receipts -- ' |
| 39 |
. $status . " (JSON):\n"; |
| 40 |
$minimal = array( |
| 41 |
'status' => $status, |
| 42 |
'source' => self::textField($record, 'source'), |
| 43 |
'session_key' => self::textField($record, 'session_key'), |
| 44 |
'plugin_version' => self::textField($record, 'plugin_version'), |
| 45 |
'missing_required_evidence' => |
| 46 |
is_array($record['missing_required_evidence'] ?? null) |
| 47 |
? $record['missing_required_evidence'] : array(), |
| 48 |
'interpretation' => is_array($record['interpretation'] ?? null) |
| 49 |
? $record['interpretation'] : null, |
| 50 |
'reduced' => 'over_budget', |
| 51 |
); |
| 52 |
foreach (array($record, $minimal) as $candidate) { |
| 53 |
$line = json_encode(array(self::INTERPRETATION_KEY => $candidate)); |
| 54 |
if (is_string($line) |
| 55 |
&& strlen($header) + strlen($line) |
| 56 |
<= self::MAX_CANARY_RECEIPT_INTERPRETATION_BYTES) { |
| 57 |
return $header . $line; |
| 58 |
} |
| 59 |
} |
| 60 |
return $header . 'The receipt interpretation record could not be encoded for this payload.'; |
| 61 |
} |
| 62 |
|
| 63 |
/** @param array<array-key, mixed> $record */ |
| 64 |
private static function textField(array $record, string $field): string { |
| 65 |
$value = $record[$field] ?? null; |
| 66 |
return is_scalar($value) ? (string)$value : ''; |
| 67 |
} |
| 68 |
} |
| 69 |
|