Forum teuk.org

🧭 MB678-III — Give Partyline Dispatch Its Own Marauder's Map Without Changing the Route

in Mediabot · started by TeuK · 3d ago

TeuK · 3d ago

MB678 continues the progressive decomposition of Mediabot’s Partyline subsystem.

After separating the transport layer in MB678-I and the session/authentication layer in MB678-II, this round isolates the central Partyline dispatcher: the _handle_line method that decides where each incoming Partyline line must go.

The objective was deliberately narrow: move routing responsibility out of the large Mediabot::Partyline module without changing the protocol, command syntax, authentication flow, command implementations, or historical method surface.


🗺️ What moved

MB678-III introduces:

Mediabot/Partyline/Dispatcher.pm

and moves exactly one method into it:

_handle_line

That method remains responsible for:

  • per-session input throttling;
  • authentication-state routing;
  • nickname/password progression;
  • authenticated Partyline command dispatch;
  • command argument forwarding;
  • unknown-command handling;
  • normal Partyline chat fallback.

The command implementations themselves remain in:

Mediabot/Partyline.pm

This is intentional.

MB678-III creates the routing boundary first; command extraction is reserved for the next Partyline round.

The historical call surface is preserved by importing _handle_line back into Mediabot::Partyline, so existing callers and tests can continue to use:

$partyline->_handle_line(...)

without knowing that the implementation now lives in Mediabot::Partyline::Dispatcher.


🧱 Structural result

Before MB678-III:

Mediabot/Partyline.pm : 5426 lines

After MB678-III:

Mediabot/Partyline.pm             : 5046 lines
Mediabot/Partyline/Dispatcher.pm  :  407 lines
Mediabot/Partyline/SessionAuth.pm :  676 lines
Mediabot/Partyline/Transport.pm   : 1012 lines

The Partyline subsystem now has three explicit responsibility boundaries:

Partyline.pm
    command implementations and remaining core Partyline behaviour

Partyline/Dispatcher.pm
    line routing and command dispatch

Partyline/SessionAuth.pm
    session lifecycle and authentication

Partyline/Transport.pm
    TCP / DCC transport and low-level input handling

The dispatcher extraction removes roughly 380 lines of routing logic from the parent module while preserving the existing Partyline API.


🧪 Focused validation

A dedicated extraction contract was added:

t/cases/864_mb678_partyline_dispatcher_extraction.t

The focused dispatcher validation covered the new extraction contract together with existing transport, session/authentication, module-structure, export, and throttle contracts.

Result:

PASSED : 703/703

This included the important:

779_mb596_partyline_throttle_hardening.t

which exercises runtime behaviour around _handle_line, rather than only inspecting source structure.


🧩 Contract traps discovered and fixed

Moving _handle_line exposed several historical tests that treated physical source location as part of the contract.

The runtime behaviour was correct, but those tests still searched only:

Mediabot/Partyline.pm

for routing code that now legitimately lives in:

Mediabot/Partyline/Dispatcher.pm

No production-code rollback was made.

Instead, the affected source contracts were updated to inspect the correct module set.

Fast-suite contracts

The first fast run reported three failures:

FAILED : 3/5640

They came from:

21_partyline_schedule_control.t
237_partyline_quota_cmd.t

The stale assumptions concerned:

  • .schedule routing;
  • the unique .ban dispatch block;
  • .quota routing.

Those tests now inspect Partyline.pm + Dispatcher.pm where appropriate.

Targeted result:

PASSED : 26/26

Full-only contracts

The first full run reported:

FAILED : 4/14552

The four failures were all source-location assumptions:

587_mb368_atomic_config_reload.t
780_mb597_precommit_hardening.t
836_mb654_achievement_identity_diagnostics.t

They covered:

  • .reloadconf routing;
  • flood-boot close-before-cleanup ordering;
  • .achievementprofile dispatch;
  • .achievementprofile argument forwarding.

The tests were updated so their source contracts follow the new architecture:

Partyline.pm + Dispatcher.pm

or, for the flood/transport invariant:

Partyline.pm + Transport.pm + Dispatcher.pm

Targeted result:

PASSED : 101/101

These failures were architectural test debt, not runtime regressions.


🛡️ Security audit

The security audit remained completely green after the extraction.

Final result:

Verdict: GO — all 11 security invariants hold.

Among the preserved guarantees:

  • external commands continue to use shell-safe execution;
  • IRC output retains CR/LF/NUL neutralisation;
  • the single-instance process lock remains enforced;
  • HTTP download caps remain active;
  • authentication throttling remains present on both IRC and Partyline paths.

The Partyline authentication-throttling invariant remained intact despite _handle_line moving into its own module.


🔌 Real runtime validation

The development instance was restarted successfully:

mediabot@dev.service
Active: active (running)

The Partyline listener remained available on:

0.0.0.0:23456

A real TCP smoke test against the Partyline produced:

Mediabot Partyline

Please enter your nickname.

Enter your password.

with:

RC_SMOKE=0

This is an important runtime check for MB678-III.

The nickname line now passes through the extracted dispatcher, which correctly recognizes the session state and routes execution into the authentication flow.

No obvious runtime errors were found in the service journal.


⚡ Fast suite

After updating the stale source contracts:

PASSED : 5640/5640  (64s)

No fast-suite regression remained.


🏰 Full suite

The final complete test suite passed:

PASSED : 14552/14552  (207s)

This validates the extraction across the complete Mediabot regression surface, including the full-only source and behaviour contracts.


🧠 Why this matters

Before this round, the Partyline transport and authentication layers had already been separated, but routing still lived inside the large parent module.

MB678-III establishes a clean dispatcher boundary.

That matters because Partyline now has a much clearer flow:

Transport
    ↓
Dispatcher
    ↓
Session/Auth or command implementation

The new structure makes it easier to reason about:

  • where input enters the system;
  • where authentication state is evaluated;
  • where command routing happens;
  • where commands themselves are implemented.

It also makes the next extraction safer.

The remaining large block in Partyline.pm is now predominantly command implementation code. That gives MB678-IV a much better starting point for extracting Partyline commands without mixing transport, authentication, and routing concerns into the same change.

Just as importantly, this round preserved compatibility.

No Partyline protocol change was introduced.

No command syntax changed.

No authentication behaviour changed.

No public Partyline method disappeared.

The architecture changed; the route did not.


📦 Commit

Version : 3.4dev-20260820_162844
Commit  : ff633dc
Branch  : master

🧭 Give Partyline Dispatch Its Own Marauder's Map Without Changing the Route

Commit summary:

14 files changed
507 insertions
393 deletions

New files:

Mediabot/Partyline/Dispatcher.pm
t/cases/864_mb678_partyline_dispatcher_extraction.t

The commit was successfully pushed to GitHub.


🧭 The corridors have not changed, and every door still leads where it did before. Partyline simply has a Marauder’s Map now.

You must be logged in to reply.