Compare commits
5
Commits
f2fddeb87d
...
1be259b66d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1be259b66d | ||
|
|
2c3c88d067 | ||
|
|
3fc14d16bf | ||
|
|
4cc50889d6 | ||
|
|
63e68740b6 |
Executable → Regular
+16
-16
@@ -18,6 +18,22 @@
|
|||||||
# WebGUI slowdowns or timeouts under load.
|
# WebGUI slowdowns or timeouts under load.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# OPERATIONAL MODEL
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Each run snapshots:
|
||||||
|
# inotify: instances in use vs INOTIFY_MAX_INSTANCES kernel limit.
|
||||||
|
# Top 5 consumers by instance count. Warns above INOTIFY_WARN_PCT.
|
||||||
|
# php-fpm: active workers vs PHP_MAX_CHILDREN limit.
|
||||||
|
# Warns above PHP_FPM_WARN_PCT.
|
||||||
|
#
|
||||||
|
# Log line format (one per run, trimmed to TUNING_LOG_RETENTION days):
|
||||||
|
# DATE|TIME|INOTIFY_USED|INOTIFY_LIMIT|INOTIFY_PCT|INOTIFY_WARN|
|
||||||
|
# PHPFPM_ACTIVE|PHPFPM_MAX|PHPFPM_PCT|PHPFPM_WARN
|
||||||
|
# INOTIFY_WARN and PHPFPM_WARN are 1/0 flags. weekly_health_digest.sh counts
|
||||||
|
# warnings over the week to show trend severity.
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
# DESIGN PRINCIPLES
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -36,22 +52,6 @@
|
|||||||
# signal — routine snapshots below the threshold produce nothing.
|
# signal — routine snapshots below the threshold produce nothing.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# OPERATIONAL MODEL
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Each run snapshots:
|
|
||||||
# inotify: instances in use vs INOTIFY_MAX_INSTANCES kernel limit.
|
|
||||||
# Top 5 consumers by instance count. Warns above INOTIFY_WARN_PCT.
|
|
||||||
# php-fpm: active workers vs PHP_MAX_CHILDREN limit.
|
|
||||||
# Warns above PHP_FPM_WARN_PCT.
|
|
||||||
#
|
|
||||||
# Log line format (one per run, trimmed to TUNING_LOG_RETENTION days):
|
|
||||||
# DATE|TIME|INOTIFY_USED|INOTIFY_LIMIT|INOTIFY_PCT|INOTIFY_WARN|
|
|
||||||
# PHPFPM_ACTIVE|PHPFPM_MAX|PHPFPM_PCT|PHPFPM_WARN
|
|
||||||
# INOTIFY_WARN and PHPFPM_WARN are 1/0 flags. weekly_health_digest.sh counts
|
|
||||||
# warnings over the week to show trend severity.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL SAFEGUARDS
|
# OPERATIONAL SAFEGUARDS
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
Executable → Regular
+18
-18
@@ -14,24 +14,6 @@
|
|||||||
# into a single digest. Reads only — writes nothing, changes nothing.
|
# into a single digest. Reads only — writes nothing, changes nothing.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Aggregator, Not Generator
|
|
||||||
# This script reads state files that other scripts maintain. It never produces
|
|
||||||
# health data itself — it only presents what is already there. Each source
|
|
||||||
# script remains responsible for its own state; this script is the envelope.
|
|
||||||
#
|
|
||||||
# Profile-Driven Notification
|
|
||||||
# The cron schedule never changes. The DIGEST_PROFILE in master.conf controls
|
|
||||||
# when notifications actually send — switching from daily noise to weekly
|
|
||||||
# summaries is a one-line conf change, not a cron edit.
|
|
||||||
#
|
|
||||||
# Read-Only, No Side Effects
|
|
||||||
# Writes nothing, changes nothing, triggers nothing. Safe to run at any time
|
|
||||||
# for a health snapshot without affecting any running service or state file.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL MODEL
|
# OPERATIONAL MODEL
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -58,6 +40,24 @@
|
|||||||
# RAMDISK_PATH / TRANSCODE_LINK — current transcode location and usage
|
# RAMDISK_PATH / TRANSCODE_LINK — current transcode location and usage
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# DESIGN PRINCIPLES
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Aggregator, Not Generator
|
||||||
|
# This script reads state files that other scripts maintain. It never produces
|
||||||
|
# health data itself — it only presents what is already there. Each source
|
||||||
|
# script remains responsible for its own state; this script is the envelope.
|
||||||
|
#
|
||||||
|
# Profile-Driven Notification
|
||||||
|
# The cron schedule never changes. The DIGEST_PROFILE in master.conf controls
|
||||||
|
# when notifications actually send — switching from daily noise to weekly
|
||||||
|
# summaries is a one-line conf change, not a cron edit.
|
||||||
|
#
|
||||||
|
# Read-Only, No Side Effects
|
||||||
|
# Writes nothing, changes nothing, triggers nothing. Safe to run at any time
|
||||||
|
# for a health snapshot without affecting any running service or state file.
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# OPERATIONAL SAFEGUARDS
|
# OPERATIONAL SAFEGUARDS
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
Executable → Regular
+18
-18
@@ -15,6 +15,24 @@
|
|||||||
# comparison. In --dry-run mode, console only — nothing written to the log.
|
# comparison. In --dry-run mode, console only — nothing written to the log.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# OPERATIONAL MODEL
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Five report sections (each skips gracefully if its data source is unavailable):
|
||||||
|
#
|
||||||
|
# ZFS pool health — status, state, errors per pool. Pools in
|
||||||
|
# ZFS_REPORT_IGNORE_POOLS excluded from the report
|
||||||
|
# (still fully monitored by unRAID — report-only exclusion).
|
||||||
|
# ARC statistics — current ARC vs max, metadata pressure, hit rate.
|
||||||
|
# Warns if ARC utilisation exceeds ZFS_REPORT_ARC_WARN_PCT, or if
|
||||||
|
# ARC headroom (max - current) drops below ZFS_REPORT_ARC_FREE_WARN_GB.
|
||||||
|
# Memory status — total, free, available RAM (informational only — see note below).
|
||||||
|
# Warns if available < ZFS_REPORT_AVAIL_WARN_GB.
|
||||||
|
# Docker memory — top ZFS_REPORT_DOCKER_TOP containers by memory usage.
|
||||||
|
# Useful for spotting containers approaching watchdog limits.
|
||||||
|
# Kernel pressure — vmstat snapshot (3 samples).
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
# DESIGN PRINCIPLES
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -42,24 +60,6 @@
|
|||||||
# reclaimable cache) is still checked separately as a true system-pressure signal.
|
# reclaimable cache) is still checked separately as a true system-pressure signal.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# OPERATIONAL MODEL
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Five report sections (each skips gracefully if its data source is unavailable):
|
|
||||||
#
|
|
||||||
# ZFS pool health — status, state, errors per pool. Pools in
|
|
||||||
# ZFS_REPORT_IGNORE_POOLS excluded from the report
|
|
||||||
# (still fully monitored by unRAID — report-only exclusion).
|
|
||||||
# ARC statistics — current ARC vs max, metadata pressure, hit rate.
|
|
||||||
# Warns if ARC utilisation exceeds ZFS_REPORT_ARC_WARN_PCT, or if
|
|
||||||
# ARC headroom (max - current) drops below ZFS_REPORT_ARC_FREE_WARN_GB.
|
|
||||||
# Memory status — total, free, available RAM (informational only — see note below).
|
|
||||||
# Warns if available < ZFS_REPORT_AVAIL_WARN_GB.
|
|
||||||
# Docker memory — top ZFS_REPORT_DOCKER_TOP containers by memory usage.
|
|
||||||
# Useful for spotting containers approaching watchdog limits.
|
|
||||||
# Kernel pressure — vmstat snapshot (3 samples).
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL SAFEGUARDS
|
# OPERATIONAL SAFEGUARDS
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
Executable → Regular
+13
-13
@@ -18,6 +18,19 @@
|
|||||||
# total. Too high wastes RAM; too low causes slowdowns.
|
# total. Too high wastes RAM; too low causes slowdowns.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# OPERATIONAL MODEL
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# 1. Read the current pm.max_children from the PHP-FPM pool config
|
||||||
|
# 2. Already at or above the target → exit silently, no write, no restart
|
||||||
|
# 3. Otherwise rewrite the value and restart PHP-FPM via the adapter
|
||||||
|
# 4. Verify PHP-FPM came back up
|
||||||
|
#
|
||||||
|
# Runs at array start, before the WebGUI sees real load. The setting does not survive an
|
||||||
|
# unRAID update — the OS replaces the pool config — which is why this reapplies every boot
|
||||||
|
# rather than being a one-time install step.
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
# DESIGN PRINCIPLES
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -41,19 +54,6 @@
|
|||||||
# 7. Read back config to confirm value applied
|
# 7. Read back config to confirm value applied
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# OPERATIONAL MODEL
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# 1. Read the current pm.max_children from the PHP-FPM pool config
|
|
||||||
# 2. Already at or above the target → exit silently, no write, no restart
|
|
||||||
# 3. Otherwise rewrite the value and restart PHP-FPM via the adapter
|
|
||||||
# 4. Verify PHP-FPM came back up
|
|
||||||
#
|
|
||||||
# Runs at array start, before the WebGUI sees real load. The setting does not survive an
|
|
||||||
# unRAID update — the OS replaces the pool config — which is why this reapplies every boot
|
|
||||||
# rather than being a one-time install step.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL SAFEGUARDS
|
# OPERATIONAL SAFEGUARDS
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
Executable → Regular
+14
-14
@@ -14,20 +14,6 @@
|
|||||||
# page always reflects the live key value.
|
# page always reflects the live key value.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Self-Healing at Boot
|
|
||||||
# The unraid-api registry is ephemeral — OS updates and service restarts clear
|
|
||||||
# it without warning. Running at every array start means the key is always
|
|
||||||
# present after boot without any manual intervention.
|
|
||||||
#
|
|
||||||
# Conf Stays Current
|
|
||||||
# HOST*_UNRAID_API_KEY in the local host conf is updated after every renewal.
|
|
||||||
# The partnership page reads the conf — it always reflects the live key value
|
|
||||||
# without a separate sync step.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL MODEL
|
# OPERATIONAL MODEL
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -42,6 +28,20 @@
|
|||||||
# a key present in the conf but absent from the registry is the exact failure it repairs.
|
# a key present in the conf but absent from the registry is the exact failure it repairs.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# DESIGN PRINCIPLES
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Self-Healing at Boot
|
||||||
|
# The unraid-api registry is ephemeral — OS updates and service restarts clear
|
||||||
|
# it without warning. Running at every array start means the key is always
|
||||||
|
# present after boot without any manual intervention.
|
||||||
|
#
|
||||||
|
# Conf Stays Current
|
||||||
|
# HOST*_UNRAID_API_KEY in the local host conf is updated after every renewal.
|
||||||
|
# The partnership page reads the conf — it always reflects the live key value
|
||||||
|
# without a separate sync step.
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# OPERATIONAL SAFEGUARDS
|
# OPERATIONAL SAFEGUARDS
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -16,12 +16,7 @@
|
|||||||
# Not scheduled and deliberately not in any orchestrator. This is a development check — it runs
|
# Not scheduled and deliberately not in any orchestrator. This is a development check — it runs
|
||||||
# when the routing changes, not every night. Nothing on the running system depends on it.
|
# when the routing changes, not every night. Nothing on the running system depends on it.
|
||||||
#
|
#
|
||||||
# RUNTIME MODES
|
# DESIGN PRINCIPLES
|
||||||
# ai_explain_check.sh check every fixture
|
|
||||||
# ai_explain_check.sh --verbose print the full explain report for each case
|
|
||||||
# ai_explain_check.sh <pattern> only cases whose question matches the pattern
|
|
||||||
#
|
|
||||||
# OPERATIONAL SAFEGUARDS
|
|
||||||
# Asserts routing, never wording.
|
# Asserts routing, never wording.
|
||||||
# Which capabilities a profile holds and which evidence was attached are decided before the
|
# Which capabilities a profile holds and which evidence was attached are decided before the
|
||||||
# model is asked anything. Asserting on generated prose would fail for reasons that tell
|
# model is asked anything. Asserting on generated prose would fail for reasons that tell
|
||||||
@@ -31,8 +26,16 @@
|
|||||||
# An unrecognised key is an error, not a skip. A typo in an assertion that silently passes
|
# An unrecognised key is an error, not a skip. A typo in an assertion that silently passes
|
||||||
# is worse than no assertion, because the line still reads as covered.
|
# is worse than no assertion, because the line still reads as covered.
|
||||||
#
|
#
|
||||||
|
# OPERATIONAL SAFEGUARDS
|
||||||
|
# Read-only. Runs fixtures through --explain and compares; writes nothing and changes no state.
|
||||||
|
#
|
||||||
# Exits non-zero on any failure, so it can gate a commit.
|
# Exits non-zero on any failure, so it can gate a commit.
|
||||||
#
|
#
|
||||||
|
# RUNTIME MODES
|
||||||
|
# ai_explain_check.sh check every fixture
|
||||||
|
# ai_explain_check.sh --verbose print the full explain report for each case
|
||||||
|
# ai_explain_check.sh <pattern> only cases whose question matches the pattern
|
||||||
|
#
|
||||||
# DEPENDS ON
|
# DEPENDS ON
|
||||||
# Plugin/unraid/Tools/ai_chat_worker.php --explain mode
|
# Plugin/unraid/Tools/ai_chat_worker.php --explain mode
|
||||||
# Plugin/unraid/Tools/ai_explain_fixtures.txt
|
# Plugin/unraid/Tools/ai_explain_fixtures.txt
|
||||||
|
|||||||
Executable → Regular
+13
-13
@@ -15,19 +15,6 @@
|
|||||||
# Accepts --host=HOST2 to refresh a single host (used by the UI refresh button).
|
# Accepts --host=HOST2 to refresh a single host (used by the UI refresh button).
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Cache-First, Never Live on Page Load
|
|
||||||
# Remote arr APIs have non-trivial latency — calling them on every page view
|
|
||||||
# would make the arrs page slow and fragile. Writing to /tmp/vv_cache/ on a
|
|
||||||
# 2-hour schedule decouples page load time from network availability.
|
|
||||||
#
|
|
||||||
# Single-Host Refresh for UI
|
|
||||||
# The UI refresh button passes --host=HOSTN to update one host without waiting
|
|
||||||
# for the full 2-hour cycle. Keeps the cache fresh when a user requests it.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL MODEL
|
# OPERATIONAL MODEL
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -44,6 +31,19 @@
|
|||||||
# back to live calls when a file is missing or stale.
|
# back to live calls when a file is missing or stale.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# DESIGN PRINCIPLES
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Cache-First, Never Live on Page Load
|
||||||
|
# Remote arr APIs have non-trivial latency — calling them on every page view
|
||||||
|
# would make the arrs page slow and fragile. Writing to /tmp/vv_cache/ on a
|
||||||
|
# 2-hour schedule decouples page load time from network availability.
|
||||||
|
#
|
||||||
|
# Single-Host Refresh for UI
|
||||||
|
# The UI refresh button passes --host=HOSTN to update one host without waiting
|
||||||
|
# for the full 2-hour cycle. Keeps the cache fresh when a user requests it.
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# OPERATIONAL SAFEGUARDS
|
# OPERATIONAL SAFEGUARDS
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
// state, tier activation, handback strikes, covered container status — for the fallback
|
// state, tier activation, handback strikes, covered container status — for the fallback
|
||||||
// tab's 30s poll.
|
// tab's 30s poll.
|
||||||
//
|
//
|
||||||
|
// OPERATIONAL MODEL
|
||||||
|
// Computed fresh on every request, deliberately uncached. The inputs are small local state
|
||||||
|
// files that fallback.sh rewrites as it moves between states, so assembling them costs about
|
||||||
|
// nothing — and a cached fallback picture is the one kind of stale this tab must never serve.
|
||||||
|
// A page showing NORMAL because the answer was cached before the switch is worse than a page
|
||||||
|
// that took an extra moment to load.
|
||||||
|
//
|
||||||
// DESIGN PRINCIPLES
|
// DESIGN PRINCIPLES
|
||||||
// Thin transport. Every judgement about what a state file means lives in
|
// Thin transport. Every judgement about what a state file means lives in
|
||||||
// include/fallback.php. This file exists to give the browser a URL.
|
// include/fallback.php. This file exists to give the browser a URL.
|
||||||
|
|||||||
+16
-11
@@ -4,12 +4,19 @@
|
|||||||
// Active media sessions endpoint. Normalised now-playing across every Emby, Jellyfin and
|
// Active media sessions endpoint. Normalised now-playing across every Emby, Jellyfin and
|
||||||
// Plex instance configured for this host, for the monitor page's session panel.
|
// Plex instance configured for this host, for the monitor page's session panel.
|
||||||
//
|
//
|
||||||
|
// OPERATIONAL MODEL
|
||||||
|
// Local is the default and stays the cheap path: one call per media server configured on this
|
||||||
|
// host. Mesh adds one bounded SSH hop per partner and is only requested while the operator is
|
||||||
|
// looking at the mesh view, so a dashboard left open on the default costs exactly what it did
|
||||||
|
// before the scope existed.
|
||||||
|
//
|
||||||
// DESIGN PRINCIPLES
|
// DESIGN PRINCIPLES
|
||||||
// Thin transport. Discovery, per-server API dialects and normalisation all live in
|
// Thin transport. Discovery, per-server API dialects and normalisation all live in
|
||||||
// include/media.php; this file only sets the content type and encodes the result.
|
// include/media.php; this file only sets the content type and encodes the result.
|
||||||
//
|
//
|
||||||
// No parameters. Which servers to ask is derived from conf, not from the request, so the
|
// The request chooses a scope, never a target. scope= selects local or mesh; which servers
|
||||||
// browser cannot point this endpoint at an arbitrary URL.
|
// are asked, and which partners the mesh hop reaches, are both derived from conf. The browser
|
||||||
|
// can widen what it asks for, but it cannot point this endpoint at an arbitrary URL.
|
||||||
//
|
//
|
||||||
// OPERATIONAL SAFEGUARDS
|
// OPERATIONAL SAFEGUARDS
|
||||||
// Bounded by the library's 3s per-request timeout.
|
// Bounded by the library's 3s per-request timeout.
|
||||||
@@ -25,18 +32,16 @@
|
|||||||
// messages a client.
|
// messages a client.
|
||||||
//
|
//
|
||||||
// REQUEST
|
// REQUEST
|
||||||
// GET, no parameters
|
|
||||||
//
|
|
||||||
// RESPONSE
|
|
||||||
// vv_media_sessions() verbatim — a flat list of normalised sessions across all servers
|
|
||||||
//
|
|
||||||
// REQUEST
|
|
||||||
// GET this host's sessions
|
// GET this host's sessions
|
||||||
// GET ?scope=mesh every node's sessions, each row tagged with the host it is playing on
|
// GET ?scope=mesh every node's sessions, each row tagged with the host it is playing on
|
||||||
//
|
//
|
||||||
// Local is the default and stays the cheap path: one call per configured media server here.
|
// RESPONSE
|
||||||
// Mesh adds one bounded SSH hop per partner and is only requested while the operator is looking
|
// local {"scope":"local","sessions":[…],"server_names":[…],"server_count":N}
|
||||||
// at the mesh view, so a dashboard left open on the default costs exactly what it did before.
|
// mesh {"scope":"mesh","nodes":[…],"sessions":[…],"server_names":[…],"server_count":N}
|
||||||
|
//
|
||||||
|
// sessions is the normalised list; in the mesh scope each row also carries the host it is
|
||||||
|
// playing on. server_count counts media servers, not sessions. There is no error shape — an
|
||||||
|
// unreachable server contributes nothing; see OPERATIONAL SAFEGUARDS.
|
||||||
//
|
//
|
||||||
// DEPENDS ON
|
// DEPENDS ON
|
||||||
// include/media.php vv_media_sessions(), vv_media_sessions_mesh()
|
// include/media.php vv_media_sessions(), vv_media_sessions_mesh()
|
||||||
|
|||||||
@@ -4,12 +4,19 @@
|
|||||||
// The Partnership tab's mesh chat: read a channel, post to it, forget a message on this
|
// The Partnership tab's mesh chat: read a channel, post to it, forget a message on this
|
||||||
// machine, and mark a channel read.
|
// machine, and mark a channel read.
|
||||||
//
|
//
|
||||||
// REQUEST
|
// OPERATIONAL MODEL
|
||||||
// GET channels + this host's id + unread counts
|
// The method is the routing. Anything that is not a POST is a read — channel list or one
|
||||||
// GET ?channel=<id> that channel's messages
|
// channel's messages — and every POST carries an action. That keeps the CSRF boundary and the
|
||||||
// POST action=send channel=<id> text=… [color=#rrggbb] [font=mono|sans|serif]
|
// read/write boundary on the same line, so a mutation cannot arrive un-covered by being
|
||||||
// POST action=delete channel=<id> id=<msgid> local only
|
// spelled as a GET.
|
||||||
// POST action=read channel=<id> mark seen up to now
|
//
|
||||||
|
// Reads are computed per request, not cached. Unread counts come from walking the last 200
|
||||||
|
// messages of each channel against this host's read mark; the card polls on a slow cycle and
|
||||||
|
// the store is a small append log, so a cache would add a staleness class for no gain.
|
||||||
|
//
|
||||||
|
// Delivery is not part of the response's success. vv_nc_send() writes locally and spools for
|
||||||
|
// any partner that could not be reached, and the reply carries that spool depth as `queued`.
|
||||||
|
// A sleeping partner is a pending message, not a failed one.
|
||||||
//
|
//
|
||||||
// DESIGN PRINCIPLES
|
// DESIGN PRINCIPLES
|
||||||
// Read marks are local and per channel. "Unread" is a fact about this operator at this
|
// Read marks are local and per channel. "Unread" is a fact about this operator at this
|
||||||
@@ -28,6 +35,22 @@
|
|||||||
// locally and spooled for retry; saying "failed" over something that is stored and queued
|
// locally and spooled for retry; saying "failed" over something that is stored and queued
|
||||||
// would be the wrong claim.
|
// would be the wrong claim.
|
||||||
//
|
//
|
||||||
|
// REQUEST
|
||||||
|
// GET channels + this host's id + unread counts
|
||||||
|
// GET ?channel=<id> that channel's messages
|
||||||
|
// POST action=send channel=<id> text=… [color=#rrggbb] [font=mono|sans|serif]
|
||||||
|
// POST action=delete channel=<id> id=<msgid> local only
|
||||||
|
// POST action=read channel=<id> mark seen up to now
|
||||||
|
//
|
||||||
|
// RESPONSE
|
||||||
|
// {"ok":true,"me":<host>,"channels":[{…,"unread":N}],"hostnames":{id:name}} channel list
|
||||||
|
// {"ok":true,"me":<host>,"channel":<id>,"messages":[…],"last_read":<ts>} one channel
|
||||||
|
// {"ok":true,"msg":{…},"queued":N} send; N = spooled
|
||||||
|
// {"ok":true|false} delete
|
||||||
|
// {"ok":true} read
|
||||||
|
// {"ok":false,"error":"Unknown channel"|"Nothing to send"|"Could not store message"
|
||||||
|
// |"No message id"|"Unknown action"}
|
||||||
|
//
|
||||||
// DEPENDS ON
|
// DEPENDS ON
|
||||||
// include/node_chat.php
|
// include/node_chat.php
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
// reachability, SSH trust, conf-sync state and the shared-service inventory — for the
|
// reachability, SSH trust, conf-sync state and the shared-service inventory — for the
|
||||||
// partnership tab's poll.
|
// partnership tab's poll.
|
||||||
//
|
//
|
||||||
|
// OPERATIONAL MODEL
|
||||||
|
// One call, one document. The endpoint holds no logic and adds no cache of its own — it
|
||||||
|
// encodes whatever vv_partnership_all() returns, so any freshness policy is the library's and
|
||||||
|
// there is only one place it can be changed.
|
||||||
|
//
|
||||||
|
// The whole picture is assembled per request rather than exposed as separate endpoints for
|
||||||
|
// hosts, trust and services. Those answers are read together and judged against each other —
|
||||||
|
// a host that is reachable but has lost SSH trust is a different state from either fact alone,
|
||||||
|
// and splitting them would let the tab render a combination that never existed at one moment.
|
||||||
|
//
|
||||||
// DESIGN PRINCIPLES
|
// DESIGN PRINCIPLES
|
||||||
// Thin transport. Host enumeration, SSH probing and trust evaluation live in
|
// Thin transport. Host enumeration, SSH probing and trust evaluation live in
|
||||||
// include/partnership.php; this file only sets the content type and encodes.
|
// include/partnership.php; this file only sets the content type and encodes.
|
||||||
|
|||||||
@@ -4,6 +4,19 @@
|
|||||||
// Script and document reader. Returns the full text of one .sh or .md file inside
|
// Script and document reader. Returns the full text of one .sh or .md file inside
|
||||||
// SCRIPTS_DIR — the source view behind the scheduler page's script viewer and the docs tab.
|
// SCRIPTS_DIR — the source view behind the scheduler page's script viewer and the docs tab.
|
||||||
//
|
//
|
||||||
|
// OPERATIONAL MODEL
|
||||||
|
// Validate, resolve, read. The id is checked against a character class and an extension list
|
||||||
|
// before it is joined to SCRIPTS_DIR, so nothing reaches the filesystem that did not already
|
||||||
|
// look like a repo-relative path.
|
||||||
|
//
|
||||||
|
// The whole file is returned in one response — no ranges, no pagination. These are scripts and
|
||||||
|
// documents, not logs; the largest is a few hundred kilobytes, and a viewer that had to stitch
|
||||||
|
// pages together would be more machinery than the thing it displays.
|
||||||
|
//
|
||||||
|
// Every failure is a JSON body with ok:false, never an HTTP error code. The scheduler's viewer
|
||||||
|
// and the docs tab both parse the response before looking at anything else, so a 404 would
|
||||||
|
// surface as a parse failure rather than as "that file is not there".
|
||||||
|
//
|
||||||
// DESIGN PRINCIPLES
|
// DESIGN PRINCIPLES
|
||||||
// Two extensions, one endpoint.
|
// Two extensions, one endpoint.
|
||||||
// Scripts and their READMEs are read the same way because they are read for the same
|
// Scripts and their READMEs are read the same way because they are read for the same
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
// resource, docker, system, storage, network and stability — together with the thresholds
|
// resource, docker, system, storage, network and stability — together with the thresholds
|
||||||
// each one is judging against, for the watchdog tab's poll.
|
// each one is judging against, for the watchdog tab's poll.
|
||||||
//
|
//
|
||||||
|
// OPERATIONAL MODEL
|
||||||
|
// Served from a 5-minute cache unless ?live is present. Assembling this payload reads every
|
||||||
|
// watchdog's state files and resolves every threshold out of master.conf, which is far more
|
||||||
|
// work than the tab's poll needs — the watchdogs themselves only run every 15 minutes, so a
|
||||||
|
// fresher answer would describe the same cycle.
|
||||||
|
//
|
||||||
|
// The cache is consulted before include/watchdog.php is even loaded, so a cache hit costs one
|
||||||
|
// file read and nothing else. ?live skips the read, recomputes, and writes the result back, so
|
||||||
|
// an explicit refresh also benefits the next visitor rather than being discarded.
|
||||||
|
//
|
||||||
// DESIGN PRINCIPLES
|
// DESIGN PRINCIPLES
|
||||||
// Thin transport. State-file parsing and threshold resolution live in
|
// Thin transport. State-file parsing and threshold resolution live in
|
||||||
// include/watchdog.php; this file only sets the content type and encodes.
|
// include/watchdog.php; this file only sets the content type and encodes.
|
||||||
@@ -15,7 +25,9 @@
|
|||||||
// against, so the page never has to fetch the two independently and risk mismatching
|
// against, so the page never has to fetch the two independently and risk mismatching
|
||||||
// them across a conf edit.
|
// them across a conf edit.
|
||||||
//
|
//
|
||||||
// No parameters. Which watchdogs exist is fixed by the codebase, not by the request.
|
// The only parameter is a freshness override. ?live decides how old an answer may be, never
|
||||||
|
// what is in it — which watchdogs exist is fixed by the codebase, and no request can select,
|
||||||
|
// filter or widen the set.
|
||||||
//
|
//
|
||||||
// OPERATIONAL SAFEGUARDS
|
// OPERATIONAL SAFEGUARDS
|
||||||
// Read-only. Nothing here clears a strike, lifts a skip-list entry, restarts a container,
|
// Read-only. Nothing here clears a strike, lifts a skip-list entry, restarts a container,
|
||||||
|
|||||||
@@ -8,31 +8,53 @@
|
|||||||
// the prompt on its own. A proposal is filed; the operator accepts or dismisses it; accepted
|
// the prompt on its own. A proposal is filed; the operator accepts or dismisses it; accepted
|
||||||
// text lands in the learned memory slot, which the prompt explicitly ranks BELOW retrieval.
|
// text lands in the learned memory slot, which the prompt explicitly ranks BELOW retrieval.
|
||||||
//
|
//
|
||||||
// WHY IT IS A PROPOSAL AND NOT A WRITE
|
// DESIGN PRINCIPLES
|
||||||
// Memory is injected into every future prompt. A model that writes its own memory writes its
|
// It is a proposal, never a write.
|
||||||
// own mistakes, and then reads them back as established fact — growing more confident on each
|
// Memory is injected into every future prompt. A model that writes its own memory writes
|
||||||
// turn while the actual source code says otherwise. The cost of a bad proposal has to be one
|
// its own mistakes, and then reads them back as established fact — growing more confident
|
||||||
// dismissal, not a permanently poisoned prompt. This is the same two-gate shape the repair
|
// on each turn while the actual source code says otherwise. The cost of a bad proposal has
|
||||||
// system uses, for the same reason: whether something should be remembered is intent, and a
|
// to be one dismissal, not a permanently poisoned prompt. This is the same two-gate shape
|
||||||
// model cannot prove intent.
|
// the repair system uses, for the same reason: whether something should be remembered is
|
||||||
|
// intent, and a model cannot prove intent.
|
||||||
//
|
//
|
||||||
// WHY DEDUP IS NOT THE MODEL'S JOB
|
// Dedup is deterministic, not the model's job.
|
||||||
// "Do I already know this" is a semantic comparison, and a 14B at IQ4_XS is confidently wrong
|
// "Do I already know this" is a semantic comparison, and a 14B at IQ4_XS is confidently
|
||||||
// at it often enough to matter — with every miss costing budget permanently. So dedup here is
|
// wrong at it often enough to matter — with every miss costing budget permanently. So
|
||||||
// deterministic: normalise, then reject on exact match or containment in either direction
|
// dedup here is deterministic: normalise, then reject on exact match or containment in
|
||||||
// against assisted memory, learned memory, and everything previously dismissed. It will let
|
// either direction against assisted memory, learned memory, and everything previously
|
||||||
// through a reworded duplicate; it will never silently drop something new, and that is the
|
// dismissed. It will let through a reworded duplicate; it will never silently drop
|
||||||
// right way round for a store the operator reviews anyway.
|
// something new, and that is the right way round for a store the operator reviews anyway.
|
||||||
//
|
//
|
||||||
// GATES
|
// OPERATIONAL SAFEGUARDS
|
||||||
// AI_MEMORY_LEARN_ENABLED false — nothing is proposed, and the prompt gains nothing
|
// Two gates, and the second cannot outrank the first.
|
||||||
// AI_MEMORY_LEARN_AUTO_ACCEPT false — accepted writes happen only when the operator says so
|
// AI_MEMORY_LEARN_ENABLED off means nothing is proposed at all, so auto-accept with
|
||||||
// The second cannot outrank the first: auto-accept with proposing off does nothing at all.
|
// proposing off does nothing. Neither defaults to on.
|
||||||
|
//
|
||||||
|
// Dismissed rows are kept, not deleted.
|
||||||
|
// They are the only thing that stops the same suggestion arriving again every night. A
|
||||||
|
// store that forgot its refusals would re-propose what the operator has already judged.
|
||||||
|
//
|
||||||
|
// Nothing here reaches the prompt directly. Accepted text lands in the learned memory slot,
|
||||||
|
// which the prompt ranks BELOW retrieval — so even an accepted mistake cannot outrank the
|
||||||
|
// source code it contradicts.
|
||||||
|
//
|
||||||
|
// EXPORTS
|
||||||
|
// Gates vv_ai_mem_learn_enabled(), vv_ai_mem_learn_auto()
|
||||||
|
// Dedup vv_ai_mem_norm(), vv_ai_mem_known(), vv_ai_mem_is_dup(), vv_ai_mem_is_ui_fact()
|
||||||
|
// Store vv_ai_mem_dir(), vv_ai_mem_propose(), vv_ai_mem_list(), vv_ai_mem_remove(),
|
||||||
|
// vv_ai_mem_append(), vv_ai_mem_write_row()
|
||||||
|
// Operator vv_ai_mem_action()
|
||||||
|
// — accept or dismiss one proposal. The only entry that changes what a future
|
||||||
|
// prompt will contain.
|
||||||
|
//
|
||||||
|
// CONFIGURATION
|
||||||
|
// master.conf
|
||||||
|
// AI_MEMORY_LEARN_ENABLED propose at all. Default false.
|
||||||
|
// AI_MEMORY_LEARN_AUTO_ACCEPT write accepted text without asking. Default false.
|
||||||
//
|
//
|
||||||
// STORE
|
// STORE
|
||||||
// data/ai/mem_proposals/<id>.json — one file per proposal, mirroring the findings store.
|
// data/ai/mem_proposals/<id>.json — one file per proposal, mirroring the findings store.
|
||||||
// States: open | accepted | dismissed. Dismissed rows are KEPT, because they are what stops
|
// States: open | accepted | dismissed.
|
||||||
// the same suggestion arriving again every night.
|
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
require_once __DIR__ . '/ai.php';
|
require_once __DIR__ . '/ai.php';
|
||||||
|
|||||||
@@ -5,47 +5,51 @@
|
|||||||
// shared chat include and every page that renders it — reads it from here instead of
|
// shared chat include and every page that renders it — reads it from here instead of
|
||||||
// restating it.
|
// restating it.
|
||||||
//
|
//
|
||||||
// WHY THIS EXISTS
|
// DESIGN PRINCIPLES
|
||||||
// A profile used to be defined in five places: history depth in api/ai.php, capabilities in
|
// One definition, not five.
|
||||||
// include/ai.php, label/hint/depth again in the chat's JavaScript, a prompt branch in the
|
// A profile used to be defined in five places: history depth in api/ai.php, capabilities
|
||||||
// worker, and a label map in pages/scheduler.php. They had already drifted — the JavaScript
|
// in include/ai.php, label/hint/depth again in the chat's JavaScript, a prompt branch in
|
||||||
// knew three profiles where PHP knew four, so the shared chat could not offer troubleshoot at
|
// the worker, and a label map in pages/scheduler.php. They had already drifted — the
|
||||||
// all and the Scheduler dock hand-rolled its own labels to compensate. The include carried a
|
// JavaScript knew three profiles where PHP knew four, so the shared chat could not offer
|
||||||
// comment telling the next person not to let the two tables diverge, which is a comment doing
|
// troubleshoot at all and the Scheduler dock hand-rolled its own labels to compensate. The
|
||||||
// a data structure's job.
|
// include carried a comment telling the next person not to let the two tables diverge,
|
||||||
|
// which is a comment doing a data structure's job.
|
||||||
//
|
//
|
||||||
// WHAT LIVES HERE, AND WHAT DELIBERATELY DOES NOT
|
// What lives here is whatever more than one file must agree on.
|
||||||
// Here: anything more than one file needs to agree on — the set of profiles, their labels and
|
// The set of profiles, their labels and hints, history depth, capabilities, and whether a
|
||||||
// hints, history depth, capabilities, and whether a profile is offered as a button.
|
// profile is offered as a button.
|
||||||
//
|
//
|
||||||
// Not here: the system prompts. They are long, delicate, and have exactly one consumer, so
|
// Not the system prompts. They are long, delicate, and have exactly one consumer, so
|
||||||
// moving them would be churn against the most sensitive text in the subsystem for no reduction
|
// moving them would be churn against the most sensitive text in the subsystem for no
|
||||||
// in duplication. Tools/ai_chat_worker.php still owns them; it just keys off ids validated
|
// reduction in duplication. Tools/ai_chat_worker.php still owns them; it just keys off ids
|
||||||
// here rather than an if-chain that invents its own vocabulary.
|
// validated here rather than an if-chain that invents its own vocabulary.
|
||||||
//
|
//
|
||||||
// CAPABILITIES ARE PER PROFILE, NOT PER CAPABILITY
|
// Capabilities are stored per profile, not per capability.
|
||||||
// The old table was inverted — capability => [profiles] — which reads well when adding a
|
// The old table was inverted — capability => [profiles] — which reads well when adding a
|
||||||
// capability and badly when answering the question actually asked at runtime, which is always
|
// capability and badly when answering the question actually asked at runtime, which is
|
||||||
// "what can this profile do". Same content, turned the right way round.
|
// always "what can this profile do". Same content, turned the right way round.
|
||||||
//
|
//
|
||||||
// A profile is a contract plus a set of inputs, and the inputs are the half that has to be
|
// A profile is a contract plus a set of inputs, and the inputs are the half that has to be
|
||||||
// enforced rather than requested. The caps list is that half.
|
// enforced rather than requested. The caps list is that half.
|
||||||
//
|
//
|
||||||
// It exists because the alternative already failed. The same permissions used to live as a
|
// OPERATIONAL SAFEGUARDS
|
||||||
// dozen `$profile === 'varaverk' || $profile === 'troubleshoot'` conditions spread across the
|
// The capability list is the grant, and it is enforced in one place.
|
||||||
// worker, and answering "may chat ever be shown a log?" meant reading all of them. It could —
|
// The same permissions used to live as a dozen `$profile === 'varaverk' || $profile ===
|
||||||
// a gate added for run-outcome questions granted it by omission, and the chat profile, whose
|
// 'troubleshoot'` conditions spread across the worker, and answering "may chat ever be
|
||||||
// entire value is that it has NOT been shown this installation, was one phrasing away from
|
// shown a log?" meant reading all of them. It could — a gate added for run-outcome
|
||||||
// being handed a health sweep and 120 lines of log. Nothing about that was visible at the
|
// questions granted it by omission, and the chat profile, whose entire value is that it
|
||||||
// point of the mistake. Here it would have been one missing word on one line.
|
// has NOT been shown this installation, was one phrasing away from being handed a health
|
||||||
|
// sweep and 120 lines of log. Nothing about that was visible at the point of the mistake.
|
||||||
|
// Here it would have been one missing word on one line.
|
||||||
//
|
//
|
||||||
// A capability is permission, not need. varaverk holds 'health' but only attaches it when the
|
// A capability is permission, not need.
|
||||||
// question looks diagnostic; troubleshoot attaches it always. The gates decide whether an
|
// varaverk holds 'health' but only attaches it when the question looks diagnostic;
|
||||||
// input is warranted, this decides whether it is allowed, and a gate can never widen the grant.
|
// troubleshoot attaches it always. The gates decide whether an input is warranted, this
|
||||||
|
// decides whether it is allowed, and a gate can never widen the grant.
|
||||||
//
|
//
|
||||||
// chat holding an empty capability list is a guarantee, not an oversight. Anything added to it
|
// chat holding an empty capability list is a guarantee, not an oversight.
|
||||||
// stops being general chat and becomes an assistant that sometimes lies about this
|
// Anything added to it stops being general chat and becomes an assistant that sometimes
|
||||||
// installation.
|
// lies about this installation.
|
||||||
//
|
//
|
||||||
// EXPORTS
|
// EXPORTS
|
||||||
// vv_ai_profiles() the whole table
|
// vv_ai_profiles() the whole table
|
||||||
|
|||||||
@@ -64,6 +64,15 @@
|
|||||||
// vv_ai_route() action → route for this node
|
// vv_ai_route() action → route for this node
|
||||||
// vv_ai_rpc() forward one action to the owner, return its response body
|
// vv_ai_rpc() forward one action to the owner, return its response body
|
||||||
//
|
//
|
||||||
|
// CONFIGURATION
|
||||||
|
// host*.conf
|
||||||
|
// <HOST>_SSH_KEY private key this node authenticates to the owner with. Absent or not a
|
||||||
|
// file means no remote route exists, and vv_ai_route() says so rather than
|
||||||
|
// attempting a hop that cannot succeed.
|
||||||
|
// <OWNER> the owner's hostname, looked up by the id vv_ai_owner_host() returns —
|
||||||
|
// resolved to an address through vv_resolve_tailscale_ip(), never used as
|
||||||
|
// a hostname directly, because MagicDNS does not resolve across the tailnets.
|
||||||
|
//
|
||||||
// DEPENDS ON
|
// DEPENDS ON
|
||||||
// include/config.php vv_ai_owner_host(), vv_ai_is_owner(), vv_resolve_tailscale_ip()
|
// include/config.php vv_ai_owner_host(), vv_ai_is_owner(), vv_resolve_tailscale_ip()
|
||||||
// Tools/ai_rpc.php the far side — reached at the WebGUI symlink path
|
// Tools/ai_rpc.php the far side — reached at the WebGUI symlink path
|
||||||
|
|||||||
@@ -43,6 +43,31 @@
|
|||||||
//
|
//
|
||||||
// Redacted before it is logged, like every other question in this subsystem.
|
// Redacted before it is logged, like every other question in this subsystem.
|
||||||
//
|
//
|
||||||
|
// EXPORTS
|
||||||
|
// Settings vv_ai_web_enabled(), vv_ai_web_provider(), vv_ai_web_results_max(),
|
||||||
|
// vv_ai_web_timeout(), vv_ai_web_searx_url(), vv_ai_web_degoog_url(),
|
||||||
|
// vv_ai_web_api_key(), vv_ai_web_ready()
|
||||||
|
// — every one reads conf; none of them reaches the network.
|
||||||
|
// Providers vv_ai_web_degoog(), vv_ai_web_searxng(), vv_ai_web_brave(), vv_ai_web_tavily()
|
||||||
|
// — one per backend, each returning the same normalised shape.
|
||||||
|
// Transport vv_ai_web_http(), vv_ai_web_normalise()
|
||||||
|
// Entry vv_ai_web_search(), vv_ai_web_context()
|
||||||
|
// — what the rest of the subsystem calls. Everything above is reachable but only
|
||||||
|
// these two are meant to be: search() picks the provider, context() formats for
|
||||||
|
// the prompt.
|
||||||
|
//
|
||||||
|
// CONFIGURATION
|
||||||
|
// master.conf
|
||||||
|
// AI_WEB_SEARCH_ENABLED master switch; anything but "true" disables the whole subsystem
|
||||||
|
// AI_WEB_SEARCH_PROVIDER which backend vv_ai_web_search() dispatches to
|
||||||
|
// AI_WEB_SEARCH_RESULTS result cap handed to the provider
|
||||||
|
// AI_WEB_SEARCH_TIMEOUT per-request timeout, in seconds
|
||||||
|
//
|
||||||
|
// host*.conf — per host, because the endpoint and the key are this machine's
|
||||||
|
// <HOST>_SEARXNG_URL self-hosted SearXNG base URL
|
||||||
|
// <HOST>_DEGOOG_URL self-hosted degoogle/Whoogle base URL
|
||||||
|
// <HOST>_WEB_SEARCH_API_KEY Brave or Tavily key, whichever provider is selected
|
||||||
|
//
|
||||||
// DEPENDS ON
|
// DEPENDS ON
|
||||||
// include/ai.php vv_ai_redact(), vv_conf_vars()
|
// include/ai.php vv_ai_redact(), vv_conf_vars()
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/common.php';
|
|
||||||
require_once __DIR__ . '/fallback.php'; // vv_fb_proc(), vv_fb_dryrun_state() — daemon liveness
|
|
||||||
require_once __DIR__ . '/partnership.php'; // vv_pt_peer_match() — tailnet name vs conf hostname
|
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
// PURPOSE
|
// PURPOSE
|
||||||
// Monitor-page roll-ups that are not raw system metrics: partner reachability, fallback
|
// Monitor-page roll-ups that are not raw system metrics: partner reachability, fallback
|
||||||
@@ -57,6 +53,10 @@ require_once __DIR__ . '/partnership.php'; // vv_pt_peer_match() — tailnet n
|
|||||||
// DATA_DIR container_restart_history.db
|
// DATA_DIR container_restart_history.db
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
require_once __DIR__ . '/common.php';
|
||||||
|
require_once __DIR__ . '/fallback.php'; // vv_fb_proc(), vv_fb_dryrun_state() — daemon liveness
|
||||||
|
require_once __DIR__ . '/partnership.php'; // vv_pt_peer_match() — tailnet name vs conf hostname
|
||||||
|
|
||||||
function vv_partner_state(): array {
|
function vv_partner_state(): array {
|
||||||
$vars = vv_conf_vars();
|
$vars = vv_conf_vars();
|
||||||
$myHostId = strtoupper(vv_detect_host());
|
$myHostId = strtoupper(vv_detect_host());
|
||||||
|
|||||||
@@ -44,6 +44,17 @@
|
|||||||
// The declaration and the markup are cross-checked at runtime. vv_mon_board_js() ships the
|
// The declaration and the markup are cross-checked at runtime. vv_mon_board_js() ships the
|
||||||
// declared ids to the page, which compares them against the cards actually present and flags
|
// declared ids to the page, which compares them against the cards actually present and flags
|
||||||
// either direction — a card in the markup nobody declared, or a declaration with no card.
|
// either direction — a card in the markup nobody declared, or a declaration with no card.
|
||||||
|
//
|
||||||
|
// EXPORTS
|
||||||
|
// Declaration vv_mon_board(), vv_mon_board_cards(), vv_mon_board_total()
|
||||||
|
// — the one array every other function here reads. Change the layout by editing
|
||||||
|
// that declaration, never by editing what follows.
|
||||||
|
// Geometry vv_mon_rung_min(), vv_mon_rung_rows(), vv_mon_rung_rowdiv(),
|
||||||
|
// vv_mon_absent_class()
|
||||||
|
// — derive the column ladder and each card's span from the declaration.
|
||||||
|
// Emitters vv_mon_board_css(), vv_mon_absorb_css(), vv_mon_board_js()
|
||||||
|
// Validation vv_mon_board_check()
|
||||||
|
// — the only one that reports rather than renders; see OPERATIONAL SAFEGUARDS.
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
// The narrowest a card may be drawn. Every breakpoint is a function of this number — see
|
// The narrowest a card may be drawn. Every breakpoint is a function of this number — see
|
||||||
|
|||||||
@@ -52,6 +52,16 @@
|
|||||||
// vv_nc_send() store + deliver to the channel's other members
|
// vv_nc_send() store + deliver to the channel's other members
|
||||||
// vv_nc_delete_local() forget one message on this machine
|
// vv_nc_delete_local() forget one message on this machine
|
||||||
// vv_nc_flush_spool() retry undelivered
|
// vv_nc_flush_spool() retry undelivered
|
||||||
|
//
|
||||||
|
// CONFIGURATION
|
||||||
|
// host*.conf
|
||||||
|
// <HOST>_SSH_KEY private key used to reach the channel's other members. Missing or not a
|
||||||
|
// file means delivery is skipped and the message is spooled — stored here
|
||||||
|
// and retried later, never reported as failed.
|
||||||
|
// <HOST> each member's hostname, looked up by the id in the channel definition.
|
||||||
|
//
|
||||||
|
// The store's own paths are defines, not conf: VV_NC_DIR under DATA_DIR/db, its .spool
|
||||||
|
// subdirectory, and VV_NC_KEEP — the per-channel message retention, fixed at 300.
|
||||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
|||||||
+24
-7
@@ -83,7 +83,8 @@ done
|
|||||||
# and handled as soft checks — see OPERATIONAL MODEL.
|
# and handled as soft checks — see OPERATIONAL MODEL.
|
||||||
spec_for() {
|
spec_for() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
sh|tools) echo "PURPOSE|OPERATIONAL MODEL|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|RUNTIME MODES" ;;
|
sh) echo "PURPOSE|OPERATIONAL MODEL|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|RUNTIME MODES" ;;
|
||||||
|
tools) echo "PURPOSE|OPERATIONAL MODEL|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|RUNTIME MODES/ARGUMENTS" ;;
|
||||||
api) echo "PURPOSE|OPERATIONAL MODEL|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|REQUEST|RESPONSE|DEPENDS ON" ;;
|
api) echo "PURPOSE|OPERATIONAL MODEL|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|REQUEST|RESPONSE|DEPENDS ON" ;;
|
||||||
include) echo "PURPOSE|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|EXPORTS" ;;
|
include) echo "PURPOSE|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|EXPORTS" ;;
|
||||||
pages) echo "PURPOSE|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|RENDERS|DEPENDS ON" ;;
|
pages) echo "PURPOSE|DESIGN PRINCIPLES|OPERATIONAL SAFEGUARDS|RENDERS|DEPENDS ON" ;;
|
||||||
@@ -91,6 +92,13 @@ spec_for() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
role_for() {
|
role_for() {
|
||||||
|
# A PHP file that refuses to run outside the CLI is a script, wherever it is filed.
|
||||||
|
# api/docker_pull_worker.php lives beside the endpoints because docker_action.php spawns it,
|
||||||
|
# but it takes argv and never a request — judging it on REQUEST and RESPONSE would mean
|
||||||
|
# inventing a contract it does not have.
|
||||||
|
if [[ "$1" == *.php ]] && grep -q "PHP_SAPI !== 'cli'" "$1" 2>/dev/null; then
|
||||||
|
echo "tools"; return
|
||||||
|
fi
|
||||||
case "$1" in
|
case "$1" in
|
||||||
*.sh) echo "sh" ;;
|
*.sh) echo "sh" ;;
|
||||||
*/Plugin/*/Tools/*.php) echo "tools" ;;
|
*/Plugin/*/Tools/*.php) echo "tools" ;;
|
||||||
@@ -130,12 +138,21 @@ while IFS= read -r f; do
|
|||||||
present=()
|
present=()
|
||||||
missing=()
|
missing=()
|
||||||
for s in "${want[@]}"; do
|
for s in "${want[@]}"; do
|
||||||
n=$(grep -c "^$m $s\$" "$f")
|
# A spec entry may name alternatives with "/". RUNTIME MODES/ARGUMENTS is the only one:
|
||||||
case "$n" in
|
# a worker that is spawned rather than run has no modes an operator can choose, and both
|
||||||
0) missing+=("$s") ;;
|
# spawned workers in the tree document ARGUMENTS instead. Demanding RUNTIME MODES there
|
||||||
1) present+=("$s") ;;
|
# would mean writing an invocation nobody performs.
|
||||||
*) present+=("$s"); problems+=("duplicate section: $s appears $n times") ;;
|
found=""
|
||||||
esac
|
IFS='/' read -ra alts <<< "$s"
|
||||||
|
for a in "${alts[@]}"; do
|
||||||
|
n=$(grep -c "^$m $a\$" "$f")
|
||||||
|
if [[ "$n" -gt 1 ]]; then
|
||||||
|
present+=("$a"); problems+=("duplicate section: $a appears $n times"); found="$a"; break
|
||||||
|
elif [[ "$n" -eq 1 ]]; then
|
||||||
|
present+=("$a"); found="$a"; break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[[ -z "$found" ]] && missing+=("${s//\// or }")
|
||||||
done
|
done
|
||||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
problems+=("missing: $(IFS=', '; echo "${missing[*]}")")
|
problems+=("missing: $(IFS=', '; echo "${missing[*]}")")
|
||||||
|
|||||||
Executable → Regular
+10
-10
@@ -20,16 +20,6 @@
|
|||||||
# know all stopped containers are safe to delete.
|
# know all stopped containers are safe to delete.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Safe Default, Explicit Escalation
|
|
||||||
# The default mode (dangling only) is always safe — running containers are
|
|
||||||
# never affected. The --all mode requires deliberate opt-in and carries an
|
|
||||||
# explicit caution in the description, because it removes stopped containers
|
|
||||||
# that may be intentionally paused.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
# OPERATIONAL MODEL
|
# OPERATIONAL MODEL
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
@@ -47,6 +37,16 @@
|
|||||||
# Reclaimed space is reported for both modes.
|
# Reclaimed space is reported for both modes.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
|
# DESIGN PRINCIPLES
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Safe Default, Explicit Escalation
|
||||||
|
# The default mode (dangling only) is always safe — running containers are
|
||||||
|
# never affected. The --all mode requires deliberate opt-in and carries an
|
||||||
|
# explicit caution in the description, because it removes stopped containers
|
||||||
|
# that may be intentionally paused.
|
||||||
|
#
|
||||||
|
# ==============================================================================================
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
#
|
#
|
||||||
|
|||||||
+10
-10
@@ -20,6 +20,16 @@
|
|||||||
# 4. Sources common.sh — shared functions: detect_hosts, logging, notifications, etc.
|
# 4. Sources common.sh — shared functions: detect_hosts, logging, notifications, etc.
|
||||||
# 5. Sources Plugin/<platform>/adapter.sh — platform_*() functions for OS-specific ops
|
# 5. Sources Plugin/<platform>/adapter.sh — platform_*() functions for OS-specific ops
|
||||||
#
|
#
|
||||||
|
# ==============================================================================================
|
||||||
|
# DESIGN PRINCIPLES
|
||||||
|
# ==============================================================================================
|
||||||
|
#
|
||||||
|
# Zero-Script Expansion
|
||||||
|
# Without this loader, adding a new server required updating every script to
|
||||||
|
# source the new host conf. With this loader: create host3.conf in the repo,
|
||||||
|
# commit and push — all servers auto-discover it on next git pull. No script
|
||||||
|
# changes required.
|
||||||
|
#
|
||||||
# USAGE IN SCRIPTS
|
# USAGE IN SCRIPTS
|
||||||
# Scripts in subdirectories (Rsync/, Docker_Essentials/ etc.):
|
# Scripts in subdirectories (Rsync/, Docker_Essentials/ etc.):
|
||||||
# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
@@ -96,16 +106,6 @@
|
|||||||
# called by the script itself afterwards.
|
# called by the script itself afterwards.
|
||||||
#
|
#
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# DESIGN PRINCIPLES
|
|
||||||
# ==============================================================================================
|
|
||||||
#
|
|
||||||
# Zero-Script Expansion
|
|
||||||
# Without this loader, adding a new server required updating every script to
|
|
||||||
# source the new host conf. With this loader: create host3.conf in the repo,
|
|
||||||
# commit and push — all servers auto-discover it on next git pull. No script
|
|
||||||
# changes required.
|
|
||||||
#
|
|
||||||
# ==============================================================================================
|
|
||||||
|
|
||||||
# ━━━ Locate config root ━━━
|
# ━━━ Locate config root ━━━
|
||||||
# load_config.sh always lives in the repo root.
|
# load_config.sh always lives in the repo root.
|
||||||
|
|||||||
Reference in New Issue
Block a user