Resolve Void persona avatar at delivery

This commit is contained in:
Meta Vens 2026-06-04 23:29:21 +01:00
commit f5c6981522
3 changed files with 61 additions and 1 deletions

View file

@ -180,6 +180,55 @@ function Get-ConfigValue {
return $null
}
function Convert-ToEnvKeySuffix {
param([string] $Value)
if ([string]::IsNullOrWhiteSpace($Value)) {
return ""
}
return (($Value.Trim().ToUpperInvariant() -replace '[^A-Z0-9]+', '_') -replace '^_+|_+$', '')
}
function Resolve-DeliveryPersonaAvatarUrl {
param(
$DeliveryTarget,
[string] $PersonaName
)
$explicitAvatarUrl = Get-ObjectPropertyString -Value $DeliveryTarget -Name "personaAvatarUrl"
if (-not [string]::IsNullOrWhiteSpace($explicitAvatarUrl)) {
return $explicitAvatarUrl.Trim()
}
if (-not [string]::IsNullOrWhiteSpace($PersonaName)) {
$personaSuffix = Convert-ToEnvKeySuffix -Value $PersonaName
if (-not [string]::IsNullOrWhiteSpace($personaSuffix)) {
$personaKey = "DISCORD_PERSONA_AVATAR_URL_$personaSuffix"
$personaAvatarUrl = Get-ConfigValue -Name $personaKey -Values $script:envValues
if (-not [string]::IsNullOrWhiteSpace($personaAvatarUrl)) {
return $personaAvatarUrl.Trim()
}
}
}
$defaultAvatarUrl = Get-ConfigValue -Name "DISCORD_PERSONA_AVATAR_URL" -Values $script:envValues
if (-not [string]::IsNullOrWhiteSpace($defaultAvatarUrl)) {
return $defaultAvatarUrl.Trim()
}
if (
-not [string]::IsNullOrWhiteSpace($PersonaName) -and
-not [string]::IsNullOrWhiteSpace($script:publicRoomPersonaName) -and
$PersonaName.Trim().Equals($script:publicRoomPersonaName.Trim(), [System.StringComparison]::OrdinalIgnoreCase) -and
-not [string]::IsNullOrWhiteSpace($script:publicRoomPersonaAvatarUrl)
) {
return $script:publicRoomPersonaAvatarUrl.Trim()
}
return $null
}
function Split-CommandArgs {
param(
[string] $Value
@ -833,7 +882,7 @@ function Invoke-CandidateInterventionDeliveryFromIntervention {
$arguments += @("--persona-name", $personaName)
}
$personaAvatarUrl = Get-ObjectPropertyString -Value $deliveryTarget -Name "personaAvatarUrl"
$personaAvatarUrl = Resolve-DeliveryPersonaAvatarUrl -DeliveryTarget $deliveryTarget -PersonaName $personaName
if (-not [string]::IsNullOrWhiteSpace($personaAvatarUrl)) {
$arguments += @("--persona-avatar-url", $personaAvatarUrl)
}

View file

@ -140,6 +140,7 @@ const contentFileIndex = process.argv.indexOf("--content-file");
const channelIndex = process.argv.indexOf("--channel-id");
const replyIndex = process.argv.indexOf("--reply-to");
const personaIndex = process.argv.indexOf("--persona-name");
const personaAvatarIndex = process.argv.indexOf("--persona-avatar-url");
if (contentFileIndex < 0 || channelIndex < 0) {
console.error("fake sender expected --content-file and --channel-id");
@ -150,6 +151,7 @@ const content = readFileSync(resolve(process.argv[contentFileIndex + 1]), "utf8"
const channelId = process.argv[channelIndex + 1];
const replyToMessageId = replyIndex >= 0 ? process.argv[replyIndex + 1] : undefined;
const personaName = personaIndex >= 0 ? process.argv[personaIndex + 1] : undefined;
const personaAvatarUrl = personaAvatarIndex >= 0 ? process.argv[personaAvatarIndex + 1] : undefined;
const payload = {
sentAt: "2026-05-17T03:01:00.000Z",
mode: "channel",
@ -157,6 +159,7 @@ const payload = {
channelId,
replyToMessageId,
personaName,
personaAvatarUrl,
contentLength: content.trim().length,
chunkCount: 1,
preview: content.trim().slice(0, 280),
@ -220,6 +223,7 @@ process.stdout.write(JSON.stringify({ ok: true, mode: "channel", channelId }) +
$previousSendScript = $env:VOID_SEND_DISCORD_SCRIPT
$previousDiscordTransport = $env:VOID_DISCORD_TRANSPORT
$previousDisableRepoCursorAdvance = $env:VOID_RUMINATION_DISABLE_REPO_CURSOR_ADVANCE
$previousVoidAvatarUrl = $env:DISCORD_PERSONA_AVATAR_URL_VOID
try {
$env:CODEX_EXECUTABLE = "node"
@ -230,6 +234,7 @@ process.stdout.write(JSON.stringify({ ok: true, mode: "channel", channelId }) +
$env:VOID_SEND_DISCORD_SCRIPT = $fakeSendPath
$env:VOID_DISCORD_TRANSPORT = "direct"
$env:VOID_RUMINATION_DISABLE_REPO_CURSOR_ADVANCE = "1"
$env:DISCORD_PERSONA_AVATAR_URL_VOID = "https://example.invalid/void-fixture-avatar.png"
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\run-void-moderator-rumination.ps1 -StateFilePath $stateFilePath | Out-Null
} finally {
@ -241,6 +246,7 @@ process.stdout.write(JSON.stringify({ ok: true, mode: "channel", channelId }) +
$env:VOID_SEND_DISCORD_SCRIPT = $previousSendScript
$env:VOID_DISCORD_TRANSPORT = $previousDiscordTransport
$env:VOID_RUMINATION_DISABLE_REPO_CURSOR_ADVANCE = $previousDisableRepoCursorAdvance
$env:DISCORD_PERSONA_AVATAR_URL_VOID = $previousVoidAvatarUrl
}
$status = Get-Content -LiteralPath $statusPath -Raw -Encoding UTF8 | ConvertFrom-Json
@ -277,6 +283,9 @@ process.stdout.write(JSON.stringify({ ok: true, mode: "channel", channelId }) +
if ($receipt.channelId -ne "fixture-channel-id" -or $receipt.replyToMessageId -ne "fixture-message-id") {
throw "Speech fixture did not preserve the delivery receipt target."
}
if ($receipt.personaName -ne "Void" -or $receipt.personaAvatarUrl -ne "https://example.invalid/void-fixture-avatar.png") {
throw "Speech fixture did not resolve the configured Void persona avatar at delivery time."
}
if ($receipt.candidateInterventionId -ne "fixture-parent-owned-speech") {
throw "Speech fixture did not link the delivery receipt back to the spoken candidate."
}

View file

@ -345,3 +345,5 @@
{"ts":"2026-06-04T20:43:18Z","type":"verification","status":"ok","note":"Rumination parent normalizes legacy top-level userStatuses model output into upsert_moderation_user_status operations; fixtures cover the stale shape and moderation status DM delivery."}
{"ts":"2026-06-04T21:00:32Z","type":"implementation","status":"ok","note":"Legacy bare moderation cursor documents with top-level userStatuses now decode through voidModerationCursorSchema into canonical cursor shape; verified build, state-boundary fixture, rumination fixture, targeted bot/worker restart, and restored a lost Nibu summon through the heartbeat path (Discord message 1512199001309446295). Separate CultCache/CultMesh Extra-byte decode still remains if it recurs outside state-note-only jobs."}
{"ts":"2026-06-04T22:20:09Z","type":"implementation","status":"ok","note":"Repo Face SAY routing now marks parent-Interpreter stale/older-side-thread routes as requiring an explicit reply_to anchor; worker refuses those SAY intents instead of defaulting to an unanchored current_room post. Verified build, agents:speech-boundary-smoke, moderation state-boundary fixture, and restarted worker PID 2488."}
{"ts":"2026-06-04T22:27:52Z","type":"implementation","status":"ok","note":"Void moderation candidate delivery now resolves persona avatar URLs at the parent delivery boundary when the model target names a persona but omits personaAvatarUrl. Speech fixture verifies Void delivery receives DISCORD_PERSONA_AVATAR_URL_VOID before direct/Bifrost transport."}
{"ts":"2026-06-04T22:29:15Z","type":"decision","status":"ok","note":"Transport doctrine updated by operator: VoidBot should expect GameCult infra and Bifrost/CultMesh transport; standalone native Discord fallback is no longer a product goal. Future cuts should remove direct VoidBot-native transport authority instead of preserving convenience for non-GameCult deployments."}