Share one AI across the mesh instead of confining it to the owner
Curated state copied to every node is state that can disagree, so the index, the model and the shared memory stay on the owner and each node reaches them over the SSH trust onboarding already builds. Chats stay on the node that had them; memory and bug reports stay the owner's to write.
This commit is contained in:
@@ -310,9 +310,25 @@ function vv_ai_finding_get(string $id): ?array {
|
||||
|
||||
// Files a finding, or increments the one already describing this fault.
|
||||
//
|
||||
// Sweeps run on every node — each reads its own logs, which is the only place they exist — but the
|
||||
// store is the AI owner's, so the operator answers one list instead of one per machine. A mirror
|
||||
// therefore forwards; the owner writes. The split is here rather than in the sweep so that every
|
||||
// caller files a finding the same way and none of them has to know where the store lives.
|
||||
//
|
||||
// $f expects: kind, subject, conf_key, conf_file, observed, evidence, source_log
|
||||
// and optionally: proposed, proven, state, note
|
||||
// and optionally: proposed, proven, state, note, host
|
||||
function vv_ai_finding_write(array $f): array {
|
||||
if (vv_ai_is_owner()) return vv_ai_finding_write_local($f);
|
||||
|
||||
require_once __DIR__ . '/ai_rpc.php';
|
||||
$status = 200;
|
||||
$r = vv_ai_rpc('finding_write', ['finding' => json_encode($f)], true, $status);
|
||||
// Not swallowed. A sweep that cannot reach the owner has found something and failed to record
|
||||
// it, and a caller told "ok" would move on and never retry.
|
||||
return is_array($r) ? $r : ['ok' => false, 'error' => 'finding_write: no response from the AI owner'];
|
||||
}
|
||||
|
||||
function vv_ai_finding_write_local(array $f): array {
|
||||
$kind = (string)($f['kind'] ?? '');
|
||||
$subject = trim((string)($f['subject'] ?? ''));
|
||||
$confKey = trim((string)($f['conf_key'] ?? ''));
|
||||
@@ -337,13 +353,18 @@ function vv_ai_finding_write(array $f): array {
|
||||
if (!isset(VV_AI_FINDING_STATES[$state])) $state = 'open';
|
||||
|
||||
$now = time();
|
||||
$id = vv_ai_finding_id($kind, $subject, $ref);
|
||||
// Which machine this finding is about, resolved once and used for both the hash and the
|
||||
// record. $f['host'] was accepted by the array below but the id was always hashed locally,
|
||||
// so a collected partner finding hashed as ours — the exact collision the host-in-the-hash
|
||||
// comment above exists to prevent.
|
||||
$host = trim((string)($f['host'] ?? '')) ?: vv_detect_host();
|
||||
$id = vv_ai_finding_id($kind, $subject, $ref, $host);
|
||||
$rec = [
|
||||
'id' => $id,
|
||||
// Which machine this is about. Written even on a single-host install, because the store
|
||||
// outlives the topology — a finding filed today is still on disk when the second node
|
||||
// arrives, and one without a host is a record nobody can place.
|
||||
'host' => (string)($f['host'] ?? vv_detect_host()),
|
||||
'host' => $host,
|
||||
'kind' => $kind,
|
||||
'subject' => mb_substr($subject, 0, 120),
|
||||
'conf_key' => $confKey,
|
||||
@@ -369,7 +390,6 @@ function vv_ai_finding_write(array $f): array {
|
||||
'severity' => vv_ai_finding_severity(['kind' => $kind, 'conf_key' => $confKey,
|
||||
'arr_type' => (string)($f['arr_type'] ?? ''),
|
||||
'sys_level' => (string)($f['sys_level'] ?? '')]),
|
||||
'host' => vv_detect_host(),
|
||||
'first' => $now,
|
||||
'last' => $now,
|
||||
'seen' => 1,
|
||||
|
||||
Reference in New Issue
Block a user