File AI-detected Varaverk defects as deduped reports, surfaced on the AI tab and counted in the coffee report
This commit is contained in:
@@ -792,6 +792,83 @@ function vv_ai_scope_ok(string $scope): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── AI-filed bug reports ─────────────────────────────────────────────────────────────────────
|
||||
// When the troubleshooter concludes the evidence shows a defect in Varaverk itself — not a
|
||||
// setting — it files a report here rather than only saying so in a chat window that closes.
|
||||
//
|
||||
// Filed automatically, with the care put into the guard rather than into a review queue: a
|
||||
// report requires a component and a quoted line of evidence, and identical findings collapse
|
||||
// onto one record with a seen count. Without that, asking the same question three times files
|
||||
// three bugs and the pile becomes noise within a week.
|
||||
//
|
||||
// Under data/ and therefore gitignored: these quote this installation's logs.
|
||||
function vv_ai_bugs_dir(): string {
|
||||
$d = DATA_DIR . '/ai_bugs';
|
||||
if (!is_dir($d)) @mkdir($d, 0755, true);
|
||||
return $d;
|
||||
}
|
||||
|
||||
// Same component + same summary is the same finding. Hashing them means a recurring fault
|
||||
// increments a counter instead of breeding files, and the count is itself the signal: seen 40
|
||||
// times is a different problem from seen once.
|
||||
function vv_ai_bug_file(array $r): string {
|
||||
return vv_ai_bugs_dir() . '/' . substr(sha1(strtolower($r['component'] . '|' . $r['summary'])), 0, 12) . '.json';
|
||||
}
|
||||
|
||||
function vv_ai_bug_write(string $component, string $summary, string $evidence, array $ctx = []): array {
|
||||
$component = trim($component);
|
||||
$summary = trim($summary);
|
||||
$evidence = trim($evidence);
|
||||
// Evidence is mandatory. A report that cannot quote the line it is based on is an opinion,
|
||||
// and this file exists to hold findings that can be checked.
|
||||
if ($component === '' || $summary === '' || $evidence === '') return ['ok' => false];
|
||||
if (!vv_ai_scope_ok($component)) return ['ok' => false];
|
||||
|
||||
$rec = [
|
||||
'component' => mb_substr($component, 0, 120),
|
||||
'summary' => mb_substr($summary, 0, 300),
|
||||
'evidence' => mb_substr($evidence, 0, 2000),
|
||||
'host' => vv_detect_host(),
|
||||
'first' => time(),
|
||||
'last' => time(),
|
||||
'seen' => 1,
|
||||
'open' => true,
|
||||
'context' => array_slice($ctx, 0, 12),
|
||||
];
|
||||
$p = vv_ai_bug_file($rec);
|
||||
if (is_file($p)) {
|
||||
$old = json_decode((string)@file_get_contents($p), true);
|
||||
if (is_array($old)) {
|
||||
$rec['first'] = $old['first'] ?? $rec['first'];
|
||||
$rec['seen'] = (int)($old['seen'] ?? 0) + 1;
|
||||
$rec['open'] = $old['open'] ?? true; // dismissing it stays dismissed
|
||||
}
|
||||
}
|
||||
$rec['id'] = basename($p, '.json');
|
||||
if (@file_put_contents($p, json_encode($rec, JSON_PRETTY_PRINT)) === false) return ['ok' => false];
|
||||
return ['ok' => true, 'id' => $rec['id'], 'seen' => $rec['seen']];
|
||||
}
|
||||
|
||||
function vv_ai_bugs_list(bool $openOnly = true): array {
|
||||
$out = [];
|
||||
foreach ((array)@glob(vv_ai_bugs_dir() . '/*.json') as $f) {
|
||||
$r = json_decode((string)@file_get_contents($f), true);
|
||||
if (!is_array($r) || ($openOnly && empty($r['open']))) continue;
|
||||
$out[] = $r;
|
||||
}
|
||||
usort($out, fn($a, $b) => ($b['last'] ?? 0) <=> ($a['last'] ?? 0));
|
||||
return $out;
|
||||
}
|
||||
|
||||
function vv_ai_bug_set_open(string $id, bool $open): bool {
|
||||
if (!preg_match('/^[0-9a-f]{12}$/', $id)) return false;
|
||||
$p = vv_ai_bugs_dir() . '/' . $id . '.json';
|
||||
$r = json_decode((string)@file_get_contents($p), true);
|
||||
if (!is_array($r)) return false;
|
||||
$r['open'] = $open;
|
||||
return @file_put_contents($p, json_encode($r, JSON_PRETTY_PRINT)) !== false;
|
||||
}
|
||||
|
||||
// ── Incident journal ─────────────────────────────────────────────────────────────────────────
|
||||
// "We have seen this before, and here is what it was." Appended as you work through logs, and
|
||||
// fed back the next time the same script is being diagnosed.
|
||||
|
||||
Reference in New Issue
Block a user