Forum teuk.org

🧭 MB688 — Let Every Instance Find Its Own Update Path

in Mediabot · started by TeuK · yesterday

TeuK · yesterday

Commit: 2dedea3fa817d36357c1a3975583f819db0a4f50
Version: 3.4dev-20260822_132722
Branch: master

MB688 started as a deployment cleanup and ended up fixing two pieces of infrastructure at once:

  1. Mediabot’s updater is now genuinely instance-generic instead of assuming one directory, one configuration file and one repository URL.
  2. The test runner now reports failures compactly by default, instead of turning two failed assertions into several pages of noise.

The common theme is simple: the tooling should understand the installation it is actually running on, and it should tell the operator exactly what matters — no more, no less. 🪄


🧭 A real Git installation, not a copied tree

The updater historically carried assumptions inherited from the original deployment layout.

Those assumptions were increasingly awkward once several Mediabot installations had to live independently.

MB688 removes the fixed-project model.

A deployment can now live in any project directory whose basename matches the safe contract:

[A-Za-z0-9][A-Za-z0-9_-]*

The updater derives all rotation paths from that real project name.

For example:

<project>.1
<project>.2
<project>.3

Temporary and failed candidate trees follow the same rule:

<project>.new.XXXXXX
<project>.failed.<pid>

No private instance name is embedded in the public code.


🌐 The current Git origin is now authoritative

install/deploy_update.sh no longer contains a hard-coded clone URL.

Instead, it resolves the current working tree’s upstream source with:

git -C "${PROJECT_DIR}" remote get-url origin

and clones the candidate release from that origin.

This changes the model in an important way:

current Git checkout
        ↓
its own origin
        ↓
validated candidate clone
        ↓
atomic directory rotation

There is no need for another Mediabot installation to act as a source tree.

No file-by-file application copy is required.

Each installation can remain an independent, normal Git checkout.


⚙️ Per-instance configuration

mediabot.conf remains the default configuration file, so the normal command is unchanged:

./install/deploy_update.sh

An installation using another private configuration can now explicitly select it:

./install/deploy_update.sh --conf=instance.conf

or:

./install/deploy_update.sh --conf instance.conf

The selected configuration must:

  • resolve to a real file;
  • live directly inside the current project root;
  • use a safe filename.

The exact selected file is preserved into the candidate release.

Mediabot::Update also forwards the bot’s actual config_file to the detached updater instead of silently falling back to mediabot.conf.

The handoff uses an argv-safe execution path:

exec { $script } @exec;

rather than rebuilding a shell command string.


🧠 Private instance state survives code rotation

Code should come from Git.

Runtime state should remain local.

MB688 makes that separation explicit.

The updater preserves:

selected instance configuration
root-level *.brn Hailo brains
var/achievements.json transitional state
mp3/

mp3/ is now explicitly ignored by Git:

mp3/

The Hailo brain logic was also simplified.

The older deployment path searched current and archived releases for a “latest” brain file.

MB688 now preserves every root-level .brn file from the current instance.

That is a safer ownership rule:

an update preserves the state of the instance being updated; it does not resurrect state from an old code archive.


🎯 Process matching now inspects the kernel’s real argv

Validation uncovered a subtle process-selection flaw.

The older updater flattened:

/proc/<pid>/cmdline

into ordinary text and then searched that text for mediabot.pl and a configuration argument.

That can create false positives.

A parent shell may contain text such as:

mediabot.pl --conf=instance.conf

inside its -c payload without being the Mediabot process itself.

MB688 now reads the real NUL-separated argv:

mapfile -d '' -t PROC_ARGV < "/proc/${PID}/cmdline"

and requires all of the following:

  • a genuine mediabot.pl argv item;
  • an actual --conf=... argument;
  • an exact match with the selected configuration file.

This prevents a shell, probe or wrapper process from being mistaken for the bot.


🛑 A failed graceful stop no longer becomes SIGKILL

The deployment path previously had an automatic escalation to:

kill -9

after the graceful shutdown timeout.

MB688 removes that behaviour.

If the selected bot process remains alive after 30 seconds, the updater now fails closed:

refusing SIGKILL and leaving the live tree untouched

That is deliberately conservative.

A deployment tool should not convert:

the application did not stop normally

into:

force-kill it and continue rotating production files

The safer outcome is to abort before the live tree is switched.


🧪 Failure output is finally compact

While validating MB688, two failed assertions exposed another usability problem.

The test runner knew exactly which assertions had failed, but --progress replayed the complete captured output for the failed files.

Two failures could therefore produce several pages of diagnostics.

The runner now follows a clearer contract.

Normal mode

Passing tests stay quiet.

Only useful failure information is shown.

--progress

The live progress display remains compact:

[====================] 100% [325/325 files | 6001 tests]

If something fails, the runner prints a bounded summary such as:

Failed test files (1)
------------------------------------------------------------
[ example_test.t ]
    [FAIL] useful assertion description

============================================================
FAILED : 1/6001  (6000 passed)
============================================================

It no longer dumps the complete TAP stream just because one assertion failed.

--verbose

Full details remain available when deep diagnosis is actually needed.

In other words:

normal      = concise
--progress  = concise + live progress
--verbose   = full diagnostic output

Failure detail is also bounded so one enormous captured value cannot flood the terminal.


🔧 Existing runner contracts were aligned, not weakened

Changing the output contract exposed several older regression tests that treated verbose formatting as if it were application behaviour.

Those tests were updated to request --verbose when they genuinely need to inspect per-test TAP output.

The affected historical guards include:

555_mb333_test_runner_isolates_exit_cases.t
842_mb660_test_classification.t
871_mb679_test_runner_progress.t

Their functional guarantees remain intact:

  • standalone TAP cases are isolated correctly;
  • assertion totals are merged into the final result;
  • test selection/classification still executes the selected cases;
  • progress mode remains compact and deterministic;
  • verbose mode still exposes full detail.

🛡️ New MB688 regression coverage

Two dedicated tests were added.

890_mb688_generic_instance_updater.t

It locks the updater’s generic-instance contract:

  • mediabot.conf remains the default;
  • --conf=<file> and --conf <file> work;
  • project names are generic but constrained;
  • archive/temp/failed trees derive from the actual project name;
  • the current Git origin drives the candidate clone;
  • process matching reads the real NUL-separated argv;
  • the selected config must match exactly;
  • no automatic SIGKILL;
  • root-level .brn files survive;
  • mp3/ survives and is ignored by Git;
  • Mediabot::Update forwards the actual instance config safely;
  • no private deployment label leaks into the public implementation.

891_mb688_test_runner_compact_failures.t

It locks the new runner contract:

  • normal failures remain concise;
  • --progress remains concise;
  • failure information remains visible;
  • large diagnostics stay hidden unless requested;
  • --verbose remains the explicit deep-debug path.

✅ Validation

The final real-host validation was deliberately layered.

Targeted MB688 regression

PASSED : 288/288

Fast validation lane

Selected: 325 of 774 discovered test file(s)

PASSED : 6001/6001
Runtime: 65s

Complete suite

PASSED : 15645/15645
Runtime: 215s

The full suite therefore validates the updater changes, the historical runner contracts and the new compact reporting behaviour together.

No database schema or migration was added by MB688.

No public runtime configuration key was introduced.

No service restart is performed by the patch itself.


📦 Commit

2dedea3fa817d36357c1a3975583f819db0a4f50
🧭 Let Every Instance Find Its Own Update Path

Version:

3.4dev-20260822_132722

Committed scope:

M  .gitignore
M  Mediabot/Update.pm
M  VERSION
M  docs/A3_deploiement_integrity.md
M  install/deploy_update.sh
M  t/cases/555_mb333_test_runner_isolates_exit_cases.t
M  t/cases/814_mb632_irc_update_command.t
M  t/cases/816_mb635_update_stage_before_stop.t
M  t/cases/842_mb660_test_classification.t
M  t/cases/871_mb679_test_runner_progress.t
A  t/cases/890_mb688_generic_instance_updater.t
A  t/cases/891_mb688_test_runner_compact_failures.t
M  t/test_commands.pl

The commit was pushed successfully to master.


🪄 What MB688 really changes

The visible code delta is an updater improvement.

The more important architectural change is the deployment model behind it:

Git owns code
instance config owns identity
runtime files own local state
systemd owns lifecycle
tests prove the boundaries

That is a much cleaner place to build the next step from.

The updater no longer needs to know which castle it lives in.

It just needs to know which Git tree, configuration and process belong to the room it is standing in. 🏰

You must be logged in to reply.