Forum teuk.org

MB708 β€” Spark Portals: three voices, one guarded spell πŸ—οΈπŸŒ€

in Mediabot Β· started by TeuK Β· 4d ago

TeuK Β· 4d ago

Mediabot v3 can now open a real collaborative Spark Portal: a short-lived channel event that invites several people to contribute, gathers their ideas safely, and produces one shared closing payoff.

This is not a free-form AI loop and it is not an excuse to bypass Spark’s existing safety model. Portal is deliberately bounded, ephemeral, generation-scoped and fully subject to the same late runtime authority checks as every other proactive Spark delivery.

Commit: 3b159ef

Version: 3.4dev-20260828_051210

Public commit message: MB708: add guarded three-voice Spark Portals β€” Mischief managed πŸ—οΈ

What a Portal does πŸͺ„

When Spark selects a Portal, Mediabot first generates and sends a compact opener. The runtime then creates an in-memory collector tied to the exact IRC channel and Spark generation.

The event follows a strict contract:

  1. It accepts one bounded contribution from each of three distinct human nicknames.
  2. Commands, direct bot triggers, bot traffic, blank/control-bearing lines and repeat contributions from the same nickname are ignored.
  3. The Portal closes immediately when the third valid contribution arrives.
  4. At the 75-second event deadline, two contributions are enough to produce the closing synthesis.
  5. Zero or one contribution remains a normal unanswered event; no artificial payoff is invented.
  6. A successful closing synthesis receives one same-channel, same-generation continuation opportunity.
  7. That continuation is single-use and expires after 120 seconds. It cannot become a general pacing bypass.

Each accepted contribution is limited to 120 characters. Collector state is kept only in memory, is capped across channels, and is discarded on completion, timeout, invalidation or runtime cleanup. No Portal transcript is written to the database.

The result feels collaborative on IRC, but the machinery underneath is closer to a carefully supervised Hogwarts classroom than an unattended Room of Requirement. 🏰

Privacy at the provider boundary πŸ•―οΈ

Portal needs the contribution text to create its shared closing line, but it does not send contributor nicknames to Anthropic, OpenAI or another configured AI provider.

The provider receives the minimum data required for the task:

  • the fixed Portal closing contract;
  • the channel language;
  • the bounded contribution text;
  • fixed generation parameters.

Contributor identity, channel identity, credentials, internal runtime objects and unrelated conversation history remain outside that request. Logs are metadata-only: they record decisions such as generation, action, reason, count and continuation state without copying contribution or generated text.

The continuation is narrow by design πŸ”

Spark already enforces a fixed 120-second delivery interval. A Portal requires an opener and, if people participate, one closing payoff during the same event. MB708 therefore adds a narrowly scoped continuation capability rather than weakening the global limiter.

The closing delivery is accepted only when all of the following still hold:

  • the event kind is portal;
  • channel and generation match the opener;
  • the continuation belongs to the same still-valid event;
  • the continuation has not already been consumed;
  • its 120-second authority window has not expired;
  • the final IRC delivery succeeds.

A rejected or failed continuation does not silently gain another attempt. The authority is explicit in sender metadata and cannot be borrowed by Reaction, Fork, Callback or VDM.

Existing guards remain authoritative πŸ›‘οΈ

MB708 preserves the complete Spark safety chain before generation and again immediately before transport:

  • the channel must still have +Spark;
  • the process-wide SPARK_SEND_ARMED kill switch must still be enabled;
  • IRC must still be connected and the bot must still be joined to the channel;
  • the channel generation must still match;
  • flood suppression must be clear;
  • active Trivia, QuoteGame and pending Wit activity retain priority;
  • conversation resumption, PART, KICK, disconnect, restart and shutdown revoke stale work;
  • provider failures and malformed output fail closed;
  • final IRC formatting and byte/character budgets still apply.

The development deployment kept its normal pacing configuration unchanged:

  • SPARK_SEND_ARMED=1
  • SPARK_MIN_SILENCE_SECONDS=1200
  • SPARK_CANDIDATE_PROBE_SECONDS=300

No database migration, schema modification, chanset addition or configuration-key change was required.

Better Spark event selection and prompts 🧭

The same commit also improves the surrounding Spark event schedule.

Selection is now context-aware and weighted rather than a simple rotation:

  • Reaction and Callback lead when recent context makes them useful;
  • Fork remains a regular but non-dominant choice;
  • Portal stays occasional, matching its more participatory nature;
  • VDM remains a rare variation and still requires +VDM.

Prompt contracts were tightened at the same time. Callback must revive a concrete recent hook. Fork may no longer turn named participants into opponents or fall back to a lazy β€œwho is right?” framing. Portal has separate opener and closing contracts so invitation and synthesis cannot be confused.

Implementation map βš™οΈ

The change introduces Mediabot::Spark::Portal as a pure collector and updates the existing Spark layers without adding another persistence system:

  • Portal.pm owns bounded collection, distinct-contributor tracking, deadline state, snapshots and cleanup.
  • Generator.pm builds separate provider-neutral opener and closing requests.
  • Sender.pm owns the single-use continuation authority and repeats every final delivery guard.
  • Orchestrator.pm observes eligible public lines through the existing flood-suppressed runtime path.
  • mediabot.pl wires opener delivery, contribution collection, immediate third-contribution closing, deadline fallback, technical-error handling and metadata-only diagnostics.

The canonical lowercase channel-cache invariant is also enforced explicitly at every Portal.pm cache boundary. This keeps Portal aligned with IRC’s case-insensitive channel identity and the historical MB407 repository contract.

Validation: the full castle inspection πŸ§ͺ🏰

The validation sequence deliberately kept the full suite until the final pre-commit gate.

Initial MB708 validation:

  • targeted Spark/VDM/MB708: 553/553 passed;
  • fast lane: 6,559/6,559 passed;
  • controlled DEV reload: passed;
  • startup, IRC login and #radiocapsule join evidence: passed;
  • corrected application-log fatal gate: passed.

The first full-suite attempt passed 17,559 of 17,560 assertions and correctly stopped the commit on the historical MB407 canonical channel-key contract. The new Portal collector already normalized its keys semantically, but seven cache accesses did not express the required explicit lc(...) boundary.

After that focused repair:

  • MB407/Spark/VDM/MB708 targeted suite: 550/550 passed;
  • fast lane: 6,559/6,559 passed;
  • controlled DEV reload and runtime readiness: passed;
  • final full-suite attempt #2: 17,560/17,560 passed in 218 seconds.

Only then was the change committed and pushed. The resulting commit contains exactly 20 project files, the upstream master branch matches local HEAD, the worktree is clean, and the private local commit.sh remains outside Git.

What happens next? πŸ”­

Portal will now be observed under normal Spark eligibility and pacing instead of distorting production rules merely to force a demonstration. Its natural runtime markers provide enough operational visibility without logging participant text.

The doorway is open, the wards are still intact, and three channel voices can finally shape one shared Spark payoff.

Mischief managed. πŸ—οΈβœ¨

You must be logged in to reply.