diff --git a/.env.example b/.env.example index f228560..8aa4f75 100644 --- a/.env.example +++ b/.env.example @@ -77,8 +77,8 @@ REPO_FACE_HEARTBEAT_IDLE_COOLING_ENABLED=true REPO_FACE_HEARTBEAT_IDLE_AFTER_MINUTES=180 REPO_FACE_HEARTBEAT_IDLE_RECOVERY_MINUTES=120 REPO_FACE_HEARTBEAT_IDLE_NAP_AFTER_MINUTES=360 -REPO_FACE_HEARTBEAT_CODEX_MODEL=gpt-5.3-codex-spark -REPO_FACE_HEARTBEAT_CODEX_MODELS=gpt-5.3-codex-spark,gpt-5.4-mini +REPO_FACE_HEARTBEAT_CODEX_MODEL=gpt-5.4 +REPO_FACE_HEARTBEAT_CODEX_MODELS=gpt-5.4 REPO_FACE_TURN_CODEX_MODEL=gpt-5.4 REPO_FACE_HEARTBEAT_CODEX_REASONING_EFFORT=low EPIPHANY_AGENT_ROOT=E:/Projects/EpiphanyAgent diff --git a/apps/worker/src/index.ts b/apps/worker/src/index.ts index d3dd044..297572f 100644 --- a/apps/worker/src/index.ts +++ b/apps/worker/src/index.ts @@ -676,16 +676,6 @@ function parseRepoFaceParentInterpretation( attempt: 1 | 2, ): RepoFaceParentInterpretation { const block = parseInterpretationBlock(interpretationText); - if (Object.keys(block).length === 0) { - const speechFallback = repoFaceInterpreterPlainSpeechFallback(interpretationText); - if (speechFallback) { - return { - decision: "route", - reasons: ["parent interpreter returned compact plain speech; wrapped it as SAY current_room"], - routedOutput: speechFallback, - }; - } - } const decision = block.decision?.trim().toLowerCase(); const parsedDecision = decision === "route" || decision === "retry" || decision === "drop" @@ -706,35 +696,6 @@ function parseRepoFaceParentInterpretation( }; } -function repoFaceInterpreterPlainSpeechFallback(interpretationText: string): string | undefined { - const content = interpretationText.trim(); - if (!content || content.length > 500) { - return undefined; - } - if (content.includes("\n\n") || parseRepoFaceActionBlocks(content).length > 0) { - return undefined; - } - if (/^(private thought|what should stick|work\/proposal|article draft|state note|interpretation)\s*:/i.test(content)) { - return undefined; - } - if (/\b(nothing public|would say nothing|stay private|hold silence|no public action|not worth routing)\b/i.test(content)) { - return undefined; - } - if (/\S(?:\.\.\.|…)$/.test(content)) { - return undefined; - } - - return [ - "SAY", - "identity: current_face_id", - "channel: current_room", - "reply_to:", - "content:", - ` ${content}`, - "END", - ].join("\n"); -} - function collectForbiddenRepoFaceChildTools(artifacts: ProviderArtifact[]): string[] { const forbidden = new Set(); for (const artifact of artifacts) { @@ -1211,7 +1172,7 @@ async function postRepoIdentityIntent(job: JobRecord, intent: RepoIdentityPostIn `Repo identity ${identity.id} SAY content is too long for one Discord message (${content.length} characters).`, ); } - if (/\S(?:\.\.\.|…)$/.test(content)) { + if (/\S(?:\.\.\.|\u2026)$/.test(content)) { throw new Error(`Repo identity ${identity.id} SAY content appears mechanically truncated.`); } const contentFile = await writeBifrostPayloadFile(job, `${identity.id}-discord-post.md`, content); diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 85ed50c..82f180f 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -16,8 +16,8 @@ Git history and smoke artifacts carry routine proof. `state/evidence.jsonl` shou ## Current Shape -- Discord bot and worker are live. -- The unattended repo Face / CTB swarm is live again as of 2026-05-21 after the teardown/restart pass. `GameCult Local Orchestrator` is enabled and owns the single hidden pulse for repo Face CTB turns, Void mood drift, Void moderation rumination, and the watchdog. Bifrost dispatch is present but disabled by default behind `BIFROST_DISPATCH_ENABLED=false`. +- Discord bot and worker may be live, but the unattended repo Face / CTB swarm brake is active as of 2026-05-26. +- The swarm was paused because live Face turns leaked owner-reply/Interpreter scaffolding into public Discord: Mind was being wrapped by the owner Discord reply prompt, then a worker fallback treated plain malformed Mind prose as public `SAY`. The fixed worker stack was restarted on 2026-05-26, typecheck/build pass, `agents:interpreter-loop-smoke` passes, and `agents:heartbeat-model-smoke -- --model gpt-5.4 --reasoning-effort none` passes. Keep `state/agent-swarm-paused.json` active until the operator explicitly asks to thaw; before thawing, run one controlled current-room turn and inspect model-output logs for `INTERPRETATION` plus explicit DSL actions only. Bifrost dispatch remains disabled by default behind `BIFROST_DISPATCH_ENABLED=false`. - The teardown authority remains `notes/agent-swarm-teardown-plan-2026-05-21.md`, but it is now a restart checklist and smell ledger rather than a stop sign. Keep using it when a Face/Bifrost/CTB boundary smells like prompt/parser/transport Jenga. - The repo-controlled pause flag is `state/agent-swarm-paused.json`. While it is missing or has `"paused": false`, swarm runners may operate. While it has `"paused": true` or is malformed, the Face heartbeat runner skips and the orchestrator skips agent-swarm organs. This is the brake. Do not route around it. - Postgres owns jobs, audit events, interaction memory, and rate-limit state. diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index 1445fca..b053a8e 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -122,8 +122,8 @@ const envSchema = z.object({ REPO_FACE_HEARTBEAT_IDLE_NAP_AFTER_MINUTES: z.coerce.number().positive().default(360), REPO_FACE_HEARTBEAT_SPEED_OVERRIDES: z.string().default(""), REPO_FACE_HEARTBEAT_HEAT_OVERRIDES: z.string().default(""), - REPO_FACE_HEARTBEAT_CODEX_MODEL: z.string().min(1).default("gpt-5.3-codex-spark"), - REPO_FACE_HEARTBEAT_CODEX_MODELS: z.string().default("gpt-5.3-codex-spark,gpt-5.4-mini"), + REPO_FACE_HEARTBEAT_CODEX_MODEL: z.string().min(1).default("gpt-5.4"), + REPO_FACE_HEARTBEAT_CODEX_MODELS: z.string().default("gpt-5.4"), REPO_FACE_IMAGINATION_CODEX_MODEL: z.string().min(1).default("gpt-5.4"), REPO_FACE_IMAGINATION_CODEX_MODELS: z.string().default("gpt-5.4"), REPO_FACE_MIND_CODEX_MODEL: z.string().min(1).default("gpt-5.4"), diff --git a/packages/providers/src/owner-codex-render.ts b/packages/providers/src/owner-codex-render.ts index cd20dda..45f49da 100644 --- a/packages/providers/src/owner-codex-render.ts +++ b/packages/providers/src/owner-codex-render.ts @@ -86,7 +86,7 @@ export function buildDiscordReplyPrompt( ] : []; - if (isRepoFaceTurn) { + if (isRepoFaceTurn || isRepoFaceParentInterpreter) { return context.prompt; } diff --git a/state/agent-swarm-paused.json b/state/agent-swarm-paused.json index 973394b..2b9ad25 100644 --- a/state/agent-swarm-paused.json +++ b/state/agent-swarm-paused.json @@ -1,5 +1,5 @@ { - "paused": false, - "reason": "Unpaused after stack restart restored ready bot/worker runtime and operations check passed live-service gates; keep watching Face prompts, interpreter routing, and memory maintenance output.", - "updatedAt": "2026-05-25T17:29:11Z" + "paused": true, + "reason": "Paused after live Face turns leaked owner-Codex/bridge artifact text into public Discord despite Face stdout choosing private silence. Fix side-effect extraction/routing before thawing.", + "updatedAt": "2026-05-26T11:29:00Z" } diff --git a/state/evidence.jsonl b/state/evidence.jsonl index f3a264c..d27b732 100644 --- a/state/evidence.jsonl +++ b/state/evidence.jsonl @@ -347,3 +347,5 @@ {"ts":"2026-05-25T21:28:29Z","type":"implementation","status":"ok","note":"Fixed repo Face CTB wake/ready split: operator-absence naps now end when operator absence ends, and the swarm dashboard includes Face rest state so napping Faces are not shown as ready. Verified build and a forced repo-face heartbeat queued Fensalir, Norn, and Nibu."} {"ts":"2026-05-26T10:53:11Z","type":"implementation","status":"ok","note":"Fixed repo Face speech loss at the Mind-to-worker crossing: if the parent interpreter returns a compact plain public sentence instead of DSL, the worker now wraps it as SAY current_room, and the interpreter prompt explicitly forbids plain-speech-only output. Verified live worker parsed say=1 and posted Mimir/Aqua webhook messages after restart."} {"ts":"2026-05-26T11:17:58Z","type":"research","status":"ok","note":"Distilled CotSC Praxis doctrine from Tao Te Ching, Bakunin, Malatesta, Rocker, Kropotkin, Goldman, and GameCult history into notes/cotsc-praxis-worldview-2026-05-26.md; repo Face prompts now carry a concise Praxis fragment emphasizing unity of means and ends, federation, mutual aid, consent, inspectability, local stewardship, Taoist non-coercive effectiveness, and rejection of Marxism-Leninist vanguard custody."} +{"ts":"2026-05-26T11:31:11Z","type":"implementation","status":"ok","note":"Paused swarm after live Face turns leaked owner-reply/Interpreter text into Discord. Root cause: parent Mind prompts were wrapped by owner-discord-reply prompt, and worker fallback converted malformed plain Interpreter output into SAY. Fixed by passing repo-face-turn-interpreter prompts through unchanged and deleting the plain-speech fallback; Spark heartbeat defaults now use gpt-5.4 because Spark quota is exhausted."} +{"ts":"2026-05-26T11:34:24Z","type":"verification","status":"ok","note":"After Mind/side-effect fix, restarted local stack with swarm pause still active. Verified npm run typecheck, npm run build, agents:interpreter-loop-smoke, and agents:heartbeat-model-smoke -- --model gpt-5.4 --reasoning-effort none. Spark default smoke failed earlier only because GPT-5.3-Codex-Spark quota is exhausted until 2026-05-31."} diff --git a/state/map.yaml b/state/map.yaml index 4092d3e..8267fb4 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -253,5 +253,5 @@ rejected_paths: reason: sleep/distillation that collapses concrete claims into generic abstraction creates memory nonsense and then forces later cleanup compensators current_status: - summary: VoidBot's bot/worker/provider/RAG/Postgres/Qdrant/CultCache structure is live again after a 2026-05-25 stack restart restored ready bot/worker PIDs. The repo Face swarm brake is lifted through `state/agent-swarm-paused.json`, `GameCult Local Orchestrator` remains the single pulse owner, repo Face heartbeats and mood drift have run `ok`, and Norn is reconciled into the active CTB participant roster. Bifrost work routing remains paused by default. - next_action: Watch the revived swarm under idle-cooling instead of forcing chatter. Verify the next human-prompted or scheduled Face turn, especially Norn's first real turn, for prompt coherence, parent Imagination/Mind routing, human-steering priority, topic-gravity pivot behavior, and sleep-memory maintenance restraint. + summary: VoidBot's bot/worker/provider/RAG/Postgres/Qdrant/CultCache structure is live, but the repo Face swarm brake is active after live turns leaked owner-reply/Interpreter text into public Discord. The fixed worker stack was restarted on 2026-05-26, parent Mind prompts now bypass the owner-reply wrapper, malformed plain Mind output no longer becomes SAY, and gpt-5.4 smoke checks pass. Bifrost work routing remains paused by default. + next_action: Keep the swarm paused until the operator explicitly asks to thaw it. Before thawing, run one controlled live repo Face turn or dry-run against the current room and confirm the latest model-output logs show an `INTERPRETATION` block plus explicit DSL actions, with no owner-reply/owner-question language crossing into Discord.