Forum teuk.org

🩺 Mediabot v3 — A Hogwarts Healer for Read-Only Diagnostics

in Mediabot · started by TeuK · 6d ago

TeuK · 6d ago

Commit: 7dc9733
Version: 3.4dev-20260817_044354

Mediabot has gained a new kind of spell: one that does not change anything.

Instead of restarting services, repairing files, changing configuration, touching MariaDB, or trying to be clever on behalf of the operator, Mediabot Doctor observes the real installation and reports what it can prove.

The first two rounds are now committed and pushed.


🏥 Meet mediabot_doctor.pl

The new tool lives here:

tools/mediabot_doctor.pl

and is tracked executable by Git.

A typical run looks like:

./tools/mediabot_doctor.pl   --root /home/mediabot/mediabot_v3   --conf /home/mediabot/mediabot_v3/mediabot.conf

Doctor is deliberately read-only.

It does not modify configuration, write to MariaDB, apply migrations, restart or stop Mediabot, edit systemd units, fetch or modify Git state, or repair deployment trees.

Its job is to tell the truth about the instance it is examining.


🧭 A fact model instead of guesses

Doctor separates three responsibilities:

collection
    ↓
evaluation
    ↓
rendering

The probes collect facts. The evaluator decides what those facts mean. The renderer presents the result as text or JSON.

A probe failure must not crash the diagnostic tool or silently become an OK.

Doctor uses explicit states:

OK
INFO
WARN
FAIL
UNKNOWN

and an overall result:

READY
DEGRADED
UNSAFE

A fact that cannot be established remains UNKNOWN with a reason. Doctor does not invent a reassuring answer.


🔐 Secrets are never collected into the fact model

Configuration inspection distinguishes required, optional and defaulted values.

Secret values are deliberately not copied into Doctor’s internal fact structure.

Doctor may report:

12 secret key(s) present

but not their contents.


🧙 Runtime verification

Doctor does more than check whether a PID file contains a number.

It verifies:

PID exists
→ process is alive
→ process command line belongs to the inspected Mediabot tree
→ running process uses the inspected configuration

This protects against stale or recycled PID files and against confusing two Mediabot instances launched from the same source tree with different configuration files.


📁 Filesystem diagnostics

The filesystem probe currently checks the important local pieces of an installation, including the main program, VERSION, module directory, sample configuration, instance configuration, PID file, log file, plugin data, project directory, parent directory and legacy achievement JSON state.

It also understands symbolic links and runtime permissions.

One useful bug was found during real-world testing.

The development configuration is:

mediabot.conf
    → mediabot.conf_20260617_1305

with:

0660 mediabot:mediabot

An early Doctor version called this too permissive.

That was wrong.

The group is a private runtime group, so the final Doctor checks the actual runtime identity and group membership before deciding whether group permissions are dangerous.

The final result is correctly:

config_file present and usable
configuration permissions 0660 use private runtime group mediabot

rather than a false warning.


🪄 Interpreter-aware executable checks

Another real installation exposed a subtler issue.

One older deployment has:

mediabot.pl mode 664

At first, Doctor reported that as a fatal error.

But the service actually launches the bot as:

/usr/bin/perl /path/to/mediabot.pl

In that execution model, the script must be readable; the kernel does not require its executable bit.

Doctor now distinguishes:

direct execution + no executable bit
    → FAIL

execution through Perl + no executable bit
    → WARN

unknown launch mode + no executable bit
    → WARN

The warning remains useful as a packaging observation without incorrectly claiming that the currently running service cannot work.


⚙️ systemd: three different truths

One of the most important design corrections was refusing to treat all systemd signals as equivalent.

Doctor keeps these separate:

runtime_manager
safe_update_marker
actual_systemd_contract

They answer three different questions:

  • was this process actually launched under systemd?
  • does the running process advertise MEDIABOT_SYSTEMD_UPDATE_SAFE=1?
  • does the actual unit satisfy the lifecycle contract expected by the built-in updater?

For the MB645 contract this includes:

Restart=always
ExitType=cgroup
SuccessExitStatus=75
RestartPreventExitStatus=75

Doctor can therefore detect disagreement instead of assuming one signal proves the others.


🧩 Probe dependencies without changing output

A particularly useful bug appeared when running only selected domains:

--domain filesystem --domain systemd --domain updater

The first implementation skipped the runtime probe entirely because it was not requested for display.

That meant filesystem and systemd lost facts such as the observed PID, runtime UID, runtime groups and launch mode, and produced false diagnostics.

The corrected model separates:

domains requested for display

from:

probes required internally as dependencies

So Doctor may silently collect runtime facts while displaying only the requested domains.

Filtering output no longer changes the reality being diagnosed.


🚂 Updater and deployment awareness

Doctor understands that not every Mediabot installation is a Git checkout and not every instance uses the built-in updater.

It can report a non-Git deployment as a supported style rather than an error.

It also understands deployment families.

For an instance rooted at:

/home/mediabot/mediabot3

Doctor recognises:

mediabot3.old.YYYYMMDD_HHMMSS

as the same deployment family while explicitly ignoring sibling families such as:

mediabot_v3.*

A real validation produced:

deployment family 'mediabot3' isolated
11 archive(s)
2 sibling-family archive(s) explicitly ignored
application root is not a Git checkout (supported deployment style)

🧠 systemd severity is evaluated in updater context

Real-world testing exposed another architectural lesson.

A service can legitimately have an older systemd lifecycle contract when the built-in updater is not applicable to that deployment.

Therefore Doctor must not blindly say:

not MB645
→ UNSAFE

The evaluator considers updater applicability when assigning severity.

The intended logic is:

built-in updater applicable
+ MB645 contract missing
→ unsafe

built-in updater not applicable
+ older coherent service contract
→ informational

safe-update marker claims MB645 support
+ real unit does not satisfy it
→ unsafe regardless

This prevents Doctor from turning “different deployment model” into “broken installation”.


🪞 Git without hidden network activity

For Git installations, Doctor can inspect working-tree changes and cached upstream divergence without fetching from the network.

A non-Git production tree is simply reported as a supported deployment style.

No fake failure.


🧪 Tests

Two dedicated test files now protect the implementation:

t/cases/828_mb647_doctor_core_local_probes.t
t/cases/829_mb648_doctor_systemd_updater.t

During development they caught several real problems, including invented configuration keys, invalid domains returning RC=0, non-existent roots returning RC=0, invalid fact levels silently degrading to INFO, runtime/config identity ambiguity, false config permission warnings, probe dependency bugs, incorrect executable-bit assumptions and systemd/updater severity without deployment context.

The final complete Mediabot suite passed:

PASSED : 13118/13118
RC=0

🏰 What Doctor covers today

The committed rounds cover:

Runtime       implemented
Config        implemented
Filesystem    implemented
systemd       implemented
Updater       implemented
Database      next round
Migrations    next round

The future database probe remains constrained by the same rule:

read-only means read-only.

It will not call a constructor that can terminate the whole diagnostic process on connection failure, and it will not invent a second schema-drift implementation.

Schema comparison will remain delegated to the existing authoritative tooling.

Migration history will also be reported honestly: because Mediabot currently has no migration ledger table, Doctor can report observable effects as:

observable_effect_present
observable_effect_missing
indeterminate

but must never pretend it can prove historical execution when no source of truth exists.


🦉 Why this change matters

The most useful result of Mediabot Doctor so far has not been a pretty health screen.

It has already forced several assumptions to prove themselves against real installations.

During development we found cases where:

a private 0660 configuration was wrongly called unsafe
a filtered command changed the diagnostic result
a Perl-launched script was wrongly considered non-runnable
an old systemd contract looked dangerous without updater context

Those are exactly the mistakes a diagnostic tool must eliminate before people trust it.

No auto-repair. No magic wand waving behind the operator’s back. Just evidence.


✨ Commit

7dc9733
🩺 Give Mediabot a Hogwarts Healer for Read-Only Diagnostics

Five files were committed, including the automatic VERSION update:

CHANGELOG.md
VERSION
tools/mediabot_doctor.pl
t/cases/828_mb647_doctor_core_local_probes.t
t/cases/829_mb648_doctor_systemd_updater.t

The spell has been pushed to GitHub.

Next stop: read-only database and migration diagnostics — still without changing the MariaDB schema.

You must be logged in to reply.