Diagnosed three chained bugs in Alma 0.0.798 that together cause "compact does nothing" — token usage never drops, the same N messages get summarized every round. The chain only fully manifests on threads using the OpenAI Codex Auth plugin (openai-codex-auth), but two of the three bugs are pure Alma main-process code and would bite any plugin that emits messages with empty inner ids.
Also reporting one UX paper cut on the Codex plugin itself.
I have a local patch running that fixes all three end-to-end so the diagnosis is grounded — but I'm filing this as a diagnostic report, not a PR, since I'm reading minified out/main/index.js.
compactThread summarizes the same messages every round (Alma main)Where: compactThread handler (POST /api/threads/:id/compact) — calls getMessagesByThreadId(threadId) and feeds the result straight into the KE summarizer.
Problem: the result is not filtered by metadata.isCompacted. So on every compaction round, messages that were already summarized in a previous round get summarized again. Indicator keeps saying "127 earlier messages were summarized" even though token count never drops.
Repro (SQL against chat_threads.db):
-- For any thread compacted multiple times:
SELECT
substr(id, -16) AS indicator_id,
datetime(substr(created_at, 1, 19)) AS created,
json_extract(metadata, '$.compactedMessageCount') AS claimed
FROM chat_messages
WHERE thread_id = '<your thread>'
AND json_extract(metadata, '$.isCompactionIndicator') = 1
ORDER BY created_at;
In one real thread I have, four consecutive rounds all claim compactedMessageCount = 127 with overlapping compactedMessageIds. Classic loop.
Suggested source-level fix: after getMessagesByThreadId, filter out rows where metadata.isCompacted === true (and metadata.isCompactionIndicator === true) before passing to KE.
Responsibility: 100% Alma. Provider-independent.
persistCompactionResult uses id-intersection, but Codex plugin emits subagent messages with id: "" (Alma + Codex plugin, joint responsibility)Where: persistCompactionResult(threadId, result, messages) — currently does roughly:
const o = new Set(result.compactedMessageIds);
for (const m of messages) {
const stripped = m.id.replace(`${threadId}--`, "");
if (o.has(stripped)) {
updateMessageMetadata(m.id, { isCompacted: true });
}
}
Problem: result.compactedMessageIds is built from e.slice(0, keepRecent).map(m => m.id) inside KE, where m is the inner message JSON, not the DB row. For subagent / tool-call rows coming from the Codex plugin, the inner message.id is an empty string. The Set ends up with "" entries that never match any actual DB id — those messages never get marked isCompacted: true, and they re-enter the compaction pool on the next round forever.
Empty inner-id is Codex-plugin-specific, not universal. Cross-tabulation against my local DB:
Claude / DeepSeek paths: zero empty ids. OpenAI Codex Auth heavy use: ~6%. Each of those 85 rows is a row that never gets marked isCompacted and re-enters the pool on every compact round.
Repro:
-- Confirm the % empty-id by model
SELECT
t.model AS model,
COUNT(*) AS total_msgs,
SUM(CASE WHEN json_extract(m.message, '$.id') = '' THEN 1 ELSE 0 END) AS empty_inner_id
FROM chat_messages m
JOIN chat_threads t ON m.thread_id = t.id
GROUP BY t.model
ORDER BY total_msgs DESC;
-- Verify claimed vs actually-written ids for a compaction indicator
SELECT
json_extract(metadata, '$.compactedMessageCount') AS claimed,
json_array_length(json_extract(metadata, '$.compactedMessageIds')) AS ids_len,
json_extract(metadata, '$.compactedMessageIds[0]') AS sample_id
FROM chat_messages
WHERE thread_id = '<your codex-backed thread>'
AND json_extract(metadata, '$.isCompactionIndicator') = 1
ORDER BY created_at DESC LIMIT 5;
On unpatched Alma I see claimed=127, ids_len=114, and a meaningful fraction of those 114 entries are the empty string.
Suggested fixes (two-sided):
Alma main (defensive, fixes the bug regardless of plugin behavior): drop the id-intersection. The contract is already "KE summarizes the first compactedMessageCount entries of its input array", so persistCompactionResult should mark by array position — take the first result.compactedMessageCount rows of messages and set isCompacted: true on each. Deterministic and immune to empty/missing inner ids.
Codex plugin (openai-codex-auth, root cause): subagent / tool-call message JSON should carry a non-empty id. Other plugins (Claude subscription, DeepSeek) already do this. Worth checking why Codex-emitted subagent rows are landing with id: "" in the stored message JSON.
Responsibility: primary cause is Codex plugin emitting empty ids; Alma's persistCompactionResult should be defensive enough not to rely on them.
KE summarizer doesn't recognize prior summary/indicator messages (Alma main)Where: the KE function — slices input by position (e.slice(0, a)), doesn't inspect text or metadata.
Problem: in the auto-compact and token-limit-triggered paths, callers pass bare message JSON (the inner parts object) and DB metadata (isCompactionIndicator, isCompactionSummary) is gone by the time it reaches KE. So previously generated summary blobs and the canonical indicator message can be re-fed into a new summary, producing nested "summary of summaries" with token bloat each round.
Suggested source-level fix: at the entry of KE, defensively filter out messages whose text starts with the canonical indicator prefix:
---\n\n🗜️ **Context Compacted**
<context_summary>
These are formats KE itself produces, so strict-prefix matching has effectively zero false-positive risk. Also pass through metadata.isCompactionSummary / isCompactionIndicator / isCompacted when the caller has them, and skip those too.
Responsibility: 100% Alma.
Where: Codex plugin (openai-codex-auth / acp-extension-codex) on Alma startup.
Problem: after a clean Alma launch, the Codex provider's models exist in settings, but Codex-backed threads behave as if the provider isn't fully initialized — instructions / tool-call behavior differ from how the same thread behaves later in the session. The fix every single time is: open Settings → Providers → Codex → click the model refresh button. After that one click, everything works for the rest of the session.
Current workaround: I literally do that refresh after every Alma start. No error message — it just silently misbehaves until refreshed.
Suspected cause (best guess from reading the bundle, would love confirmation): some piece of state (tool capability metadata? originalInstructions? a hasTools flag?) is computed lazily at provider-list refresh time, and the startup boot path doesn't reach it. The manual refresh click is what triggers metadata fetch + capability registration the agent path expects.
A defensive consumer-side fix would be something like:
const shouldInjectCodexAgentInstructions =
hasTools || !originalInstructions;
…so background paths still get correct Codex agent instructions even when per-provider lazy metadata hasn't populated yet. But the real fix is probably "always trigger the provider model refresh as part of plugin init on startup".
Repro: Cmd+Q Alma → reopen → start a Codex-backed thread → observe behavior; then Settings → refresh Codex models → return to same thread → observe corrected behavior.
Responsibility: Codex plugin.
Bugs 1+2+3 form a chain — each is annoying alone but explainable, and together they produce the "compact does nothing" symptom Codex users hit (token never drops, same N messages summarized every time). Bug 2 won't manifest at all on Claude / DeepSeek threads but is brutal on Codex Auth threads (which I suspect is a large fraction of heavy users).
Bug 4 is unrelated to compaction but affects the same plugin and has been my daily papercut for weeks.
Alma 0.0.798
macOS (Apple Silicon)
Plugin: openai-codex-auth + acp-extension-codex
Reproduced across multiple long-running Codex-backed threads (one of mine accumulated 18 compaction indicators with 0 isCompacted rows actually marked, before patching)
Happy to share redacted message-id samples, full SQL probes, or notes on the local patch I'm running (it's a binary patch on the minified bundle — not useful as a PR, but the diff is small if it helps locate the exact functions).
Thanks yetone for building Alma!
Please authenticate to join the conversation.
In Review
Bug Reports
1 day ago

Barney Hong
Get notified by email when there are changes.
In Review
Bug Reports
1 day ago

Barney Hong
Get notified by email when there are changes.