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:
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. 🪄
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.
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.
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:
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.
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.
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:
mediabot.pl argv item;--conf=... argument;This prevents a shell, probe or wrapper process from being mistaken for the bot.
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.
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.
Passing tests stay quiet.
Only useful failure information is shown.
--progressThe 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.
--verboseFull 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.
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:
Two dedicated tests were added.
890_mb688_generic_instance_updater.tIt locks the updater’s generic-instance contract:
mediabot.conf remains the default;--conf=<file> and --conf <file> work;origin drives the candidate clone;SIGKILL;.brn files survive;mp3/ survives and is ignored by Git;Mediabot::Update forwards the actual instance config safely;891_mb688_test_runner_compact_failures.tIt locks the new runner contract:
--progress remains concise;--verbose remains the explicit deep-debug path.The final real-host validation was deliberately layered.
PASSED : 288/288
Selected: 325 of 774 discovered test file(s)
PASSED : 6001/6001
Runtime: 65s
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.
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.
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.