Phase 1 exists to hand the partner its identity before the install, but the push refused any
host without varaverk.cfg — so the conf could only ever reach a node that no longer needed it
to be told who it was. It now resolves the remote's conf directory across both install layouts
and creates the internal one when neither exists.
Both checks already answered their question on demand and both needed
somebody to press a button on the right row. One host here has returned
nothing but 5xx for months.
Filed as findings, which is the existing answer to a condition that
persists while nobody is looking. Grouped by cause rather than by
hostname: a default policy of bypass produced twenty-two findings that
were one sentence repeated, and they have one fix between them.
A low uptime figure, a refused login and a certificate that stopped
renewing all looked the same from the row: a number, with the reason
split across NPM, an Authelia config and the directory.
The why-check goes and looks — TCP to the forward target, HTTP through
the proxy, a second handshake with verification off to tell a broken
certificate from a broken service. Forward hosts are docker names that
only resolve on NPM's network, so an unresolvable one is redirected to
the container address and the substitution is reported; a check that
could not be made must never read as a check that failed.
The access simulator walks the rules the way Authelia does and shows the
ones it stepped over, reading whichever instance the chosen host points
at rather than the one conf names — there are two here.
Cert triage counts runs rather than log lines and orders by rotation
suffix rather than mtime, both of which change the answer.
NPM's access log only describes hosts somebody visited; the host most likely to be quietly broken
is the one nobody does. Probes carry a User-Agent npm_access_stats.sh drops — unmarked, this
monitor would be fifty thousand requests a day in the very logs it reports on.
NPM writes an access log per host and counts nothing, so 475 MB of logs held the only answer to
"is anything using this". Aggregated on a schedule and read from a few kB of JSON; the row also
now says whether an auth_request block is in front of the site, which nothing showed before.
Saving a host sent advanced_config as an empty string and reset http2, both HSTS flags, meta,
locations and enabled — so changing a port removed the auth_request block that puts Authelia in
front of the site. Twenty-five of the thirty-five hosts here carry one.
NPM knows what a certificate is today and nothing about what it was, so ten of them could fail
renewal for months — 1001 certbot runs, zero successes — without anything on any page saying so.
Counts start at zero and are only ever observed; only first_seen is seeded, from NPM's own date.
NPM answers a successful DELETE with the bare literal true, which vv_npm_raw() is typed to
return an array from — so deleting or toggling a proxy host has always thrown a TypeError
rather than doing the thing.
Authentik is the likely destination and the page had Authelia and lldap wired in at every
level, so the seam goes in now: the panels and every endpoint action route off one conf value,
and a stack that cannot be driven yet says so rather than drawing controls with nothing behind.
Opening the editor to fix a name and then having to close it to reach a password or a group
was three dialogs for one sitting; the row buttons stay for one-click access from the list.
lldap lets you edit five things about a user and one about a group; the page reached two of
them, so correcting a surname or a group's name still meant opening the container's own WebUI.
The block is rebuilt from the parsed model on every save and the parser discarded comments,
so one press of Save deleted the five ## lines that are the only thing in the file saying
what each rule is for — which inline editing was about to make far easier to press.
Most rules carry thirteen or fourteen domains, which in one table cell was a four-hundred
character run that answered no question at a glance; the group is what you are looking for
and it is now the heading.
The value was written as typed, bash expanded it when the read-back sourced the file, and
the guard rolled the whole write back with nothing on screen but "save failed" — which is
also what an empty value, a trailing space, and a stale API-key check had been doing.
Not set, rejected and unreachable all reached the page as one message about checking
credentials, which sends you to a password when the field is simply empty — as both of
HOST1's were, with no card on the page to fill them in from.
vv_is_ai_host() was `=== 'host1'`, which made a physical fact — that is where the
GPU is — look like a rule. AI_OWNER_HOST declares it, so the card can move to a
rebuilt host3 or a friend's spare.
The gate was also doing two jobs. Assistant docks and findings strips now ask
whether a model is reachable, so a node without a GPU gets them by borrowing;
the AI tab asks whether this is the owner, because that page carries the bug
reports, the index and the model configuration — the surface where the
vocabulary assumes you built the mesh.
Resolution is local, then owner, then anyone else declaring a model, pinned once
it answers. Pinned rather than re-derived per call: a mesh that re-decides every
request eventually decides differently mid-conversation, and a chat whose second
turn lands on another machine has no history there. Cleared only on a transport
failure, and only when there is somewhere else to go — a single-node mesh whose
model is down should say so, not report AI as unconfigured.
Identity now includes the host: "Bazarr is on the skip list" is a different fact
on each machine that says it, and without the host in the hash the second node
to report a subject would land on the first node's record — one machine's
dismissal silencing another's live fault.
Nine dismissed findings existed when this changed, so the write path migrates a
legacy id once, at the only moment it matters. Verified: a dismissal survives the
rename rather than resurfacing as new.
acted_by is stamped in apply_action, not set_state — the sweep calls set_state to
move a candidate to needs_operator, and crediting a machine for classifying is
not the same as recording who decided.
The five AI_ASSIST_ switches and the findings they produce were reachable only
from the AI tab, which is a long way from the page a finding is about.
Nothing was synchronised because nothing needed to be: findings are one file per
finding, and every surface is a view over that store with actions going to the
same endpoint. Acting on the Watchdog tab shows on the AI tab because they are
not two copies. The strip reloads rather than editing its own row, which is the
only way they could have drifted apart.
Each strip shows one page's kinds. Actions are whatever the server offers for
that row, so Move appears on media findings without this card knowing what a
move is.
Declared in PHP rather than in each bash header, against scriptinfo's usual rule
that the header next to the code is authoritative: it is authoritative about what
the script does, and an enhancement is something else reading its output, gated
by a flag the script has never heard of. A description of PHP inside a file that
cannot enforce it would drift the first time either changed.
Shown with its switch, so "there is an enhancement" and "it is running" are never
the same claim. Discovery is listed even though nothing acts on its output — it
takes the first accessible root folder with no regard for content, and the
classification scan is what notices that night. That relationship explains where
misfiled series come from and was written down nowhere.
The triage could say Narcos is filed under anime and offer nothing to do about
it. Findings that recorded a destination now carry a Move action, which the AI
tab renders as a button on its own — actions are read from the server, so no UI
knew this existed. Armed like Fix and Dismiss, because it is the only action in
that card that relocates files rather than settings and the undo is another move.
Offered only where the triage said misfiled, never for uncertain: three
narrowings before a file is touched. Re-reads the series from Sonarr first, so a
finding gone stale cannot undo a move made by hand in the meantime.
The scan's own header calls reverse-anime leaks "genuine judgment calls" and
reports them as a count. Seventeen of them concealed two live-action crime
dramas filed under anime for as long as nobody read the list. The scan now
persists that bucket as its own verdict, and the sweep asks the model to sort
only those eleven — not the eleven hundred it already classifies correctly.
Files findings for misfiled and uncertain only; donghua and anime-adjacent are
answers, not problems, and filing them would rebuild the undifferentiated list
this exists to break up. Moves nothing — --move stays a flag a human types.
The grid said repeat(5,1fr) against six windows, so Fallback sat alone on a
second row. The count now travels with the cards as --vv-win-n, so adding a
window widens the row instead of quietly starting another one. Grid rather than
flex keeps every card exactly the same width, and it steps 6→3→2 rather than
dropping straight to two — the middle step is the one a 15" panel lands on.
It covers the pipeline rather than only acquisition: the arrs, the jobs that run
over the same files, and the servers that play them. The label moves; the tab id,
file and URL do not, so bookmarks and the cache key keep working.
The settings card widens with it — Play State Sync, Media Permissions, Media
Cleaner, Emby and Jellyfin were reachable only through the Settings catch-all,
which is a long way to go for a setting named after the page you are on. Match
is whole-word, so "Intermediate Sync" is not caught by "media"; section count is
unchanged at 126 with the same 5 gaps, so nothing was taken from another tab.