Commit Graph
1075 Commits
Author SHA1 Message Date
Gmer4Lfe a04368e9fc Notice when the question is about their own machine
The other detector recognises named components, so its complement is unbounded;
this one reads grammar instead, which is not.
2026-08-12 18:08:50 -04:00
Gmer4Lfe a18f0cfc84 Do not let the web note decide what the question was about
The detector answers no to "why is my array so slow", so claiming that meant a
question about the wider world would have answered it from general web pages.
2026-08-12 18:03:54 -04:00
Gmer4Lfe e1110b20df Put the counter-instruction where the refusal cannot outshout it
A paragraph beside the rule did not shift it; the ready-made refusal was simply
the nearest thing to hand, so the correction goes next to the question instead.
2026-08-12 17:53:07 -04:00
Gmer4Lfe 5b2ab93e60 Stop refusing questions about the world while holding the answer
Chat was told it could not look anything up, which is true of this machine and
false the moment a search succeeds, so it deflected while holding six sources.
2026-08-12 17:49:45 -04:00
Gmer4Lfe 533328aa91 Remember whether it may look things up
The reasoning checkbox beside it was remembered and this one was not, so ticking
it, closing the panel and coming back read as a save that had failed.
2026-08-12 17:42:31 -04:00
Gmer4Lfe 6eb84c195a Keep the memory instruction out of the answer it was attached to
Told there was nothing worth remembering, the model wrote a sentence saying so,
which is a footnote about a mechanism the operator cannot see.
2026-08-12 17:36:46 -04:00
Gmer4Lfe f8c4c93f20 Let it look things up rather than putting it in search mode
Results announced themselves as the source, so a question it already knew got
answered by paraphrasing the first hit.
2026-08-12 17:32:41 -04:00
Gmer4Lfe e2b304daad Stop proposing to remember what the UI map already says
The map documents 447 settings, so without this every question about where a
control lives earns a proposal that costs a dismissal and teaches nothing.
2026-08-12 17:26:26 -04:00
Gmer4Lfe c33f3c067b Lead with the route, since that is what was asked
Naming the conf file first got answers that sent people to edit host1.conf and
mentioned the tab afterwards.
2026-08-12 17:19:07 -04:00
Gmer4Lfe 20c17648e6 Require the registries this renderer's callers read
The AI tab included this without confform.php and referenced a constant from
it, which is a fatal, which is a blank page.
2026-08-12 17:09:03 -04:00
Gmer4Lfe 240876e710 Tell the assistant where the settings are, not just what they are called
The index reads tracked files and page markup is not one, so it could name a
conf key and never say there was a button for it.
2026-08-11 22:07:10 -04:00
Gmer4Lfe 999dbcfdf3 Give the pages one switch and one prefix each
Three pages had reimplemented the same sliding toggle, and two both claimed
vv-set-* with disjoint class names, which reads as shared and is not.
2026-08-11 21:59:27 -04:00
Gmer4Lfe 67510b8fad Draw the Scheduler's settings with the same renderer as everything else
It drew its own, so 329 of its 704 fields were text boxes that should have been
switches, numbers or lists, and 48 credentials rendered legibly.
2026-08-11 20:47:49 -04:00
Gmer4Lfe 24b526db93 Report a child's state from the list it was rendered from
Only the array name was taken from the orchestrator; the enabled flag still came
from the first-match map, so every orchestrator showed the first list's state.
2026-08-11 20:11:14 -04:00
Gmer4Lfe dfe4c0d495 Toggle the script in the orchestrator you clicked, not the first one that lists it
docker_update.sh runs bare in daily, --weekly in weekly and --remainder in
monthly, so switching it off in monthly disabled the daily run and reported
success.
2026-08-11 20:08:32 -04:00
Gmer4Lfe 2b933c45dd Give every AI setting a control, and every page one set to draw it with
The AI tab could show three per-turn checkboxes and no configuration at all;
the forty-three keys behind it were editable only by hand.
2026-08-11 19:03:12 -04:00
Gmer4Lfe f90b23ddd9 Initialise the array the write path collects refusals into
An undefined variable reaching a by-reference array parameter is a TypeError
under PHP 8, so every save through this endpoint died before writing anything.
2026-08-11 19:03:12 -04:00
Gmer4Lfe 0eccd7b36e File the repair log settings under the section that documents them
They sat under AI Web Search, which only mattered once the settings card
started grouping by the header above a key.
2026-08-11 18:36:37 -04:00
Gmer4Lfe a95def9139 Let the conf say which control each setting deserves
The comments above a setting already state its choices, units and bounds, so the
form can read them instead of asking for the file to be annotated first.
2026-08-11 18:17:04 -04:00
Gmer4Lfe 76ce424f8f Put every decision the assistant is waiting on in one place
Findings and proposed memory were two cards asking the same kind of question,
so checking one was never enough.
2026-08-11 18:00:44 -04:00
Gmer4Lfe 6855dcb8fd Watch reasoning in the same control you read it in afterwards
A capped window of its own made the block you were watching turn into a
different control the moment the answer arrived.
2026-08-11 17:37:39 -04:00
Gmer4Lfe e3ec54f213 Let each control actually govern the thing it names
Auto Scroll, the learning gate, the fold and the flash label each described a
behaviour they did not enforce.
2026-08-11 17:25:51 -04:00
Gmer4Lfe aa3d92360e Diff a proposed script against the open one and take it a hunk at a time 2026-08-10 22:41:07 -04:00
Gmer4Lfe 66f427dd2d Watch the reasoning as it is written, and hold the view where you put it 2026-08-10 22:33:57 -04:00
Gmer4Lfe 25361fafdb Let a long conversation list be filtered instead of scanned 2026-08-10 22:18:06 -04:00
Gmer4Lfe 081366a682 Fold long answers and offer a way back to the newest line 2026-08-10 22:16:11 -04:00
Gmer4Lfe 2100286dbb Show proposed memory beside findings, so keeping one is a decision and not a default 2026-08-10 22:06:28 -04:00
Gmer4Lfe 29e0daf80d Let the assistant propose what to remember, and the operator decide what is kept 2026-08-10 22:00:42 -04:00
Gmer4Lfe 57f3bf2807 Split memory into assisted and learned, and deny learned the precedence assisted has 2026-08-10 21:50:35 -04:00
Gmer4Lfe 775bdce6e1 Add slash commands, and stop Escape and recall from leaving a stale draft 2026-08-10 21:25:04 -04:00
Gmer4Lfe b9b2a59915 Let the last exchange be retried, edited or dropped, and stop losing drafts to a tab swap 2026-08-10 21:22:06 -04:00
Gmer4Lfe 33affc5a59 Open a cited script in the editor instead of a read-only viewer 2026-08-10 21:15:45 -04:00
Gmer4Lfe 9adf760c8e Give every code block its own copy and insert, and number the long ones 2026-08-10 21:12:15 -04:00
Gmer4Lfe eb24e60b8c Stream the answer as it is written, and let the operator stop it 2026-08-10 20:22:57 -04:00
Gmer4Lfe 9c744b34f8 Offer to drop an assistant's code block straight into the Scheduler editor 2026-08-10 19:59:28 -04:00
Gmer4Lfe 6054f68754 Stop conf_upgrade losing every key that follows a single-line array 2026-08-10 18:42:25 -04:00
Gmer4Lfe 74b579e281 Remove dead PCIe hardware at array start so correctable AER errors stop burying the syslog 2026-08-10 18:22:09 -04:00
Gmer4Lfe c0da7d935d Delimit the subreddit filter with ~ so it actually runs
The pattern used # as its delimiter and excluded a literal # inside the character class, so PCRE
ended the pattern early and the match never fired. It read as the filter doing nothing. The unit
test missed it by asserting against a retyped copy of the regex rather than the one in the file,
which is the only version that matters.
2026-08-09 22:55:29 -04:00
Gmer4Lfe 07f679b2e7 Drop subreddit front pages from degoog results
Its Reddit engine returns a community's landing page for any query at all — a question about ZFS
scrubs came back with Rocket League Esports and Dividend Investing, interleaved one in two, so
half of what reached the model was noise. Threads from that same engine are frequently the best
result there is, so the engine stays and only the URL shape goes: /r/<name> with nothing after it
is a front page by definition. That is a fact about the URL, not an opinion about how well it
matches, and this file does no similarity scoring of its own.
2026-08-09 22:54:42 -04:00
Gmer4Lfe 0c16c6db63 Add degoog as the search provider, and make it the default
The operator already runs it, so this is the one provider that costs nothing to adopt: no key,
no card, no third party, and no new container. It aggregates several engines and returns them
merged, and its /api/search reply is already the shape everything downstream expects — title,
url, snippet, with content as a fallback for the roughly one result in six that has no snippet.

It is also now the only provider whose response has been read from a live service rather than
from documentation, which is why it is the default.
2026-08-09 22:50:47 -04:00
Gmer4Lfe 613634473a Let General Chat search the web, and only General Chat
Search is the one capability that fits the profile holding none: every other capability either
reads this installation or changes it, and chat's whole contract is that it can do neither. The
assistant deliberately does not get it — its contract is that answers come from this install's
own documents, and a web result there is an answer that looks sourced and is not. A chat question
about this machine hands off to the assistant before the search would run, so it never reaches
the internet even with the box ticked.

Off by default, and not because it is dangerous: searching sends the operator's question outside
the house, which is theirs to decide. Asked for per turn as well as enabled in conf.

Provider-agnostic, as asked — searxng, brave, tavily. Only whichever is configured here can be
verified; all three read every field by name, so a shape that changes underneath yields no
results rather than wrong ones.

The explain fixtures asserted chat holds no capabilities at all, which is exactly the guarantee
worth keeping. caps=only: now states the set rather than its emptiness, so the check still fails
the day something else is granted there.
2026-08-09 22:42:43 -04:00
Gmer4Lfe 47861b0dc3 Pin a log-derived finding to what it is, not to what it said
The evidence of a syslog or container finding carries a line count and the timestamp of the
first matching line, so it differs on every pass even when nothing about the fault has changed.
Both the acknowledgement and the announcement were pinned to it, which meant acking one expired
fifteen minutes later and the notification repeated every sweep, forever — worst exactly where
it matters least, on a fault that has been there since the machine was built. Those kinds now
pin to their identity. A fault that genuinely worsens has a different class and so is a
different finding, and still announces on its own.
2026-08-09 22:25:51 -04:00
Gmer4Lfe 426ca2e5c7 Read the system log and the containers, not only Varaverk's own logs
Triage could see what Varaverk wrote about itself and what the arrs said about themselves, and
nothing else — so a disk throwing I/O errors, a filesystem going read-only or a PCIe link
retraining every two minutes was invisible to the thing whose job is noticing. Container state
was already watched; no line any container actually wrote ever was.

Container patterns match the environment rather than the application. Fifty containers are fifty
programs with no shared vocabulary for malfunctioning, but an exact shared one for a full disk or
a corrupt SQLite file, because those strings come from libc and SQLite rather than from the app.

Both halves are checked by Tools/ai_log_check.sh, which is two tests because the failure modes
are opposite: fixtures for recall on faults this host has never had, and a replay of its real
logs for precision — 74,519 syslog lines and 79,193 container lines, matching only the PCIe
errors it genuinely has.

Severity was being graded from a hand-picked three fields, so every one of these would have been
filed as a warning however bad it was, and notified as one.
2026-08-09 22:16:04 -04:00
Gmer4Lfe 91357a2d03 Tell the operator when a finding needs them
A finding nobody is told about is a finding nobody has, and the card added earlier only shows
them to someone who opens the tab. Only needs_operator is announced — an open finding may still
be repaired by the next pass — one notification for all of them, and each is announced once and
stays quiet until the fault changes or gets worse.

vv_notify() hands the message to common.sh's notify() rather than reimplementing the channels,
and calls detect_hosts() explicitly because load_config.sh deliberately does not: without it the
Unraid notification arrives and Discord silently never does. It also reports false when no
channel is switched on at all, since notify() exits 0 either way and a caller believing that
would mark a finding as told and never mention it again.

Notification text is folded to ASCII. Unraid's notifier dropped an em dash outright and left the
double space behind, which was found by sending one and reading what arrived.
2026-08-09 21:59:50 -04:00
Gmer4Lfe e4423200cc Report failures where the operator can still see them
The 55 alert() calls carried the same suppression as the confirms, and go wrong in the worse
direction: a silenced confirm makes a button do nothing, while a silenced alert lets the action
run and says nothing about it failing. vvAlert returns a promise nobody has to await, so these
converted by rename with no caller becoming async. The icon is inferred from the message rather
than asked of fifty call sites, and an explicit type still wins.
2026-08-09 21:47:23 -04:00
Gmer4Lfe 7d865b0a09 Ask with Unraid's own dialog, not the browser's
Every confirm() and prompt() in the plugin could be switched off from inside itself — one tick of
"prevent this page from creating additional dialogs" and all 32 of them returned false while
drawing nothing, across every tab, until a full reload. swal is already global on every webGUI
page and core uses it 370 times without a single confirm(), so this costs no new dependency.

vvConfirmRun() is the one that mattered: it returned a boolean to three callers testing !it, and
an unawaited promise is always truthy, so leaving those alone would have run every job without
asking. The wrapper's callback is a classic function expression on purpose — SweetAlert only
calls back on cancel when the callback's own source declares a parameter, and an arrow would
have hung the promise forever.
2026-08-09 21:44:43 -04:00
Gmer4Lfe 5b48561f36 Confirm a finding in the page instead of with a browser dialog
Both browsers offer "prevent this page from creating additional dialogs" inside the dialog
itself, and once it is ticked every later confirm() returns false without drawing anything — so
Fix and Never a problem silently declined and read as dead buttons. Unraid swaps tabs by AJAX
without reloading, so the suppression outlived leaving the tab and only clearing history got it
back. Both now arm on the first press and act on the second, and say what the press will do
while they wait for it.
2026-08-09 21:33:06 -04:00
Gmer4Lfe a5be719261 Refuse a conf write that widens a path to its own ancestor
Several scripts delete inside a conf path — the orphan cleaner runs rm -rf under a download dir
and rsync runs --delete against a destination — so /mnt/user/Movies becoming /mnt/user is the
edit that turns a cleanup into a sweep. Depth cannot be the test, because /tv and /movies are
real container-internal values here; direction can. Clearing a path, making it relative and
'..' segments go with it, and autofix additionally requires a proposed path to exist, since
every probe it has is a network probe and proves nothing about a directory. Refusals now reach
the caller: a save whose only change was refused answered ok with no explanation.
2026-08-09 21:21:52 -04:00
Gmer4Lfe 77fb1abb85 Put the findings where they can be answered
Seven findings had been sitting in needs_operator with no way to reach the operator: the only
way to read one was the sweep tool over SSH. The card states the gate as well as the list,
because an empty list means nothing found when repair is on and nothing is looking when it is
off. Buttons come from the actions the endpoint returned for that row, so a tab left open
overnight cannot offer a choice the store has moved past.
2026-08-09 21:14:44 -04:00
Gmer4Lfe b20a46ba81 Let an acknowledgement expire on a finding that has no conf key
An ack is supposed to hold only while the thing acknowledged is still true, but a finding with
no key compared '' against '' and so was silenced permanently — dismiss wearing ack's label,
which is every arr health finding on this host. Those pin to the shape of the fault instead.
Dismiss and reopen become real answers rather than states only reachable by editing JSON, and
apply_action now refuses anything the finding did not offer.
2026-08-09 21:14:36 -04:00