Commit Graph
260 Commits
Author SHA1 Message Date
Gmer4Lfe 74e3b8b067 Resolve docker_network_connect.sh on the mirror, and give the wizard poll time to outlast Phase 2
Step 1b ran the owner's SCRIPTS_ROOT path over SSH on the mirror, so it failed on every appdata install; the wizard poll expired at 5 minutes against a Phase 2 that takes over 4.
2026-08-17 12:12:10 -04:00
Gmer4Lfe cd21fca749 Give the wizard an ending: big checkmark plus a way out, and refresh it when the onboard lands
With nothing blocking but optional keys unfilled the banner rendered an empty string, so a finished onboard showed a blank panel beside a Join button still greyed at Running.
2026-08-17 11:47:01 -04:00
Gmer4Lfe ead5d38d7c Hide the seed strip on the mirror — it describes a push the mirror cannot make 2026-08-17 11:42:32 -04:00
Gmer4Lfe c4bfa6bdfe Show the mirror it is onboarded, and stop offering it owner-side actions
The phase-2 branch of the mirror panel returned the same Join partnership / Onboard block as the not-started state, so a finished onboard read as one that never ran.
2026-08-17 11:42:10 -04:00
Gmer4Lfe d8a77c700b Stop counting a gated-off critical rsync as an unreachable partner, and report the counter in the unit it is stored in
The guard tested Tier 1 only, so onboard Step 1d's posture — Tier 1 open, every Tier 2 closed — made a healthy partner climb toward auto-offboard every 30 minutes. The counter holds intervals, not days, and was rendered raw.
2026-08-17 11:39:19 -04:00
Gmer4Lfe 7c957d96be Make seeding Phase 3 — its own operator-triggered phase, not the tail of an onboard
Onboard now ends at Phase 2: connected, running, and saying so. Phase 3 sets the seeding gate posture and dispatches the seed. With MEDIA_SEED_ENABLED false there is no Phase 3 and the model is two phases.
2026-08-17 10:23:03 -04:00
Gmer4Lfe 1a47f864f9 Put the media seed behind MEDIA_SEED_ENABLED so a partner filled by other means never starts a multi-week transfer
Tier 2 beside the per-orchestrator gates. Unset reads as on — the toggle postdates the seed.
2026-08-17 07:46:51 -04:00
Gmer4Lfe ad623353bc Stop the media seed from holding the onboard, and therefore the partnership, open for weeks
A first seed is ~28 TB behind a 12.5 MB/s bwlimit, and it ran inline as Step 9d, so the
phase-2 flag every status reader depends on was written only after it finished.
2026-08-17 07:40:00 -04:00
Gmer4Lfe 9d2610a911 Stop the host card claiming it is waiting for a partner after the onboard was cancelled 2026-08-17 07:23:48 -04:00
Gmer4Lfe d8e3c09b57 Skip the key step when SSH already works, and read the install path live on both sides 2026-08-17 07:04:46 -04:00
Gmer4Lfe 7e7d845f61 Read the scripts dir live for the paste command, because choosing appdata moves it mid-wizard 2026-08-17 06:51:51 -04:00
Gmer4Lfe 069815790b Put the join inside the wizard, send a partner to Partnership when it finishes, and say what is left 2026-08-17 06:16:36 -04:00
Gmer4Lfe 3676526daf Remove the Docker tab and stop overwriting folder.view3's file, which destroyed folders made in its own UI 2026-08-17 05:11:00 -04:00
Gmer4Lfe 2cbc06a683 Show a launched job's progress, stop a refused rerun from overwriting the live record, and label deployed containers so Unraid owns them 2026-08-17 04:26:32 -04:00
Gmer4Lfe cce1e25c2b Let a non-blocking checklist item be dismissed with a recorded decision, and run discovery on the mirror once there is something to discover 2026-08-16 21:56:00 -04:00
Gmer4Lfe 5bdf3bff60 Report each teardown and setup step from what it did, not from whether it was attempted 2026-08-16 21:46:26 -04:00
Gmer4Lfe 3ae6298656 Let a partner adopt the owner's custom networks from the conf phase 1 already cached, instead of asking for a value it cannot know 2026-08-16 21:20:59 -04:00
Gmer4Lfe 93cdbaac57 Give the mirror the terminal step its half of phase 1 actually needs, instead of a button that cannot answer a password prompt 2026-08-16 20:16:17 -04:00
Gmer4Lfe f627658567 Read the partner's identity out of master.conf instead of asking for it again 2026-08-16 13:56:09 -04:00
Gmer4Lfe 64de77c065 Let the setup checklist create the SSH key it is asking for, instead of linking to a guide 2026-08-16 13:24:26 -04:00
Gmer4Lfe 28273ffc2a Retire domains nothing has probed in 90 days, and notice NPM changes within five minutes 2026-08-16 12:12:08 -04:00
Gmer4Lfe 7b65b64864 Let the uptime history card be folded away, and remember that per browser 2026-08-16 12:06:52 -04:00
Gmer4Lfe b90fd59544 Separate the four uptime periods so they read as four graphs, not one 2026-08-16 12:02:08 -04:00
Gmer4Lfe d5ee2d7ef1 Tell a decommissioned domain apart from a broken one in the uptime history 2026-08-16 11:59:41 -04:00
Gmer4Lfe 73358e6bae Stop Unraid's span.warn stretching the watchdog and queue badges across their row 2026-08-16 11:55:25 -04:00
Gmer4Lfe f2ad41e8e2 Show how each domain has behaved over a day, a week, a month and a year, not just now 2026-08-16 11:55:25 -04:00
Gmer4Lfe 187dc188c2 Namespace the proxy table's fixed-layout class so Unraid Connect's Tailwind layer cannot claim it 2026-08-16 11:27:59 -04:00
Gmer4Lfe ea2d3cf597 Size the proxy columns by proportion, so nothing can outgrow the page 2026-08-16 02:14:38 -04:00
Gmer4Lfe bd30c4e05a Stop the proxy table widening its own column instead of scrolling inside it 2026-08-16 02:10:22 -04:00
Gmer4Lfe 99b58c0c4f Make the Auth tab explain a number instead of only showing it
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.
2026-08-16 01:59:01 -04:00
Gmer4Lfe 1001c25487 Probe every domain every minute, and keep it out of its own traffic numbers
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.
2026-08-15 20:28:30 -04:00
Gmer4Lfe c0ace5a0ca Split requests and errors into their own columns, and label every figure
A host serving thirty-five thousand requests that are all failures read as a busy host when the
two counts sat side by side in one run of numbers.
2026-08-15 19:25:56 -04:00
Gmer4Lfe 1041c4bba8 Show what each proxy host is actually doing, and mark the ones behind Authelia
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.
2026-08-15 19:20:11 -04:00
Gmer4Lfe 3db594af86 Stop the proxy dialog wiping Custom Nginx Configuration, and let it be edited
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.
2026-08-15 19:15:54 -04:00
Gmer4Lfe 71ba0a239f Track what happens to every certificate, and show it on the Certs tab
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.
2026-08-15 18:51:38 -04:00
Gmer4Lfe 8157673291 Add AUTH_STACK so the Auth tab follows the stack in force
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.
2026-08-15 15:27:50 -04:00
Gmer4Lfe 2697b46616 Put groups, password and photo inside the user editor
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.
2026-08-15 11:54:03 -04:00
Gmer4Lfe 81aeb0619b Reach the rest of what lldap exposes — photos, real names, group rename
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.
2026-08-15 11:45:23 -04:00
Gmer4Lfe 693ac693a4 Make access-control domains an editable list, and stop saves eating the rule labels
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.
2026-08-15 11:30:36 -04:00
Gmer4Lfe b22d034933 Give each access-control rule its own card, and stop the scalar forms throwing
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.
2026-08-15 00:04:43 -04:00
Gmer4Lfe bb7c112a2d Construct the Auth tab's assistant — the markup was emitted but never wired 2026-08-14 23:53:17 -04:00
Gmer4Lfe 9eef5b50e6 Tell the three auth failures apart, and give the Auth tab a settings card
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.
2026-08-14 23:14:33 -04:00
Gmer4Lfe 90774f1442 Put the AI toggles and findings on the pages they act on
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.
2026-08-14 22:32:55 -04:00
Gmer4Lfe a705aa36b7 List each AI enhancement against the script it enhances
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.
2026-08-14 22:25:24 -04:00
Gmer4Lfe 60971f1af4 Let a misfiled series be moved from the finding that reported it
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.
2026-08-14 22:13:25 -04:00
Gmer4Lfe 2c16cc7116 Fit all six sync windows on one row
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.
2026-08-14 21:51:59 -04:00
Gmer4Lfe 5ad5c0df7e Rename the Arrs tab to Media Stack, now that it is one
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.
2026-08-14 21:47:33 -04:00
Gmer4Lfe 7f22bb0612 Run the PHP layer on the host's clock, not UTC
PHP defaults to UTC on Unraid while every bash script stamps local time, and the
two write into the same files — conf_changes.log was four hours out from every
log you would correlate it against. The parsing half was worse: vv_ai_syslog_ts()
reads local-time syslog lines through strtotime() under UTC, landing every event
four hours early, and the repair sweep bounds its scan to "since the last pass"
— so a fault that had just happened could read as four hours old and fall
outside the window. Also fixes date-string comparisons against bandwidth and
cleanup dbs, which bash writes with local dates.
2026-08-14 19:49:48 -04:00
Gmer4Lfe dbc0c8c6d2 Report container CPU as a share of the machine, matching Unraid's Docker page
docker stats sums CPU across every logical processor, so Jellyfin's "227%" is
2.3 threads busy — 7% of a 32-thread host, which is what Unraid shows and what
the operator was reading. The card was printing the raw figure and colouring it
against thresholds meant for a percentage, so ordinary background work looked
like an emergency; I twice flagged Jellyfin as pegged on that basis and was
wrong both times. Divides by nproc, not the watchdog's `cores` — that field is
the physical 16 because it compares load averages, and borrowing it here would
have looked reasonable and doubled every reading.
2026-08-14 19:39:14 -04:00
Gmer4Lfe 04a0dcb39a Let the media server card show the whole mesh, not just this host
A partner's Emby URL is http://localhost:8096 — true there, meaningless here —
so nobody queries a partner's media server directly. Each host reports its own
over the SSH call remote_arr_cache_writer.sh already makes, which keeps its API
keys on it and costs no extra connection. Local is the default: opening the tab
to check your own server should not first make you read past a partner's.
A partner with no cache is stated as not collected rather than omitted, because
an empty mesh view and a partner that is down look identical otherwise.
2026-08-14 19:30:23 -04:00