Skip to content

fix(hermes): stabilize compression and live memory writes#455

Merged
ScriptedAlchemy merged 9 commits into
masterfrom
fix/defer-live-fact-vacuum
Jul 12, 2026
Merged

fix(hermes): stabilize compression and live memory writes#455
ScriptedAlchemy merged 9 commits into
masterfrom
fix/defer-live-fact-vacuum

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

This follow-up fixes the concrete runtime defects found by reading the current Hermes gateway logs, exported Hermes transcripts, TraceDecay daemon behavior, and the live project/user stores after v0.0.59 was installed.

The native Hermes plugin remains the default and only installed TraceDecay integration. Hermes already registers the TraceDecay memory provider, context engine, command, skill overlay, and progressively discoverable native tools. No MCP server is added: a second MCP surface would duplicate the same tools and create ambiguous routing without adding capability.

Compression replay identity

The active Hermes session 20260712_003311_aac53c exposed runaway context growth. Its first compression reduced 216 messages to 193, but repeated attempts then expanded 193 to 363, 317 to 582, 416 to 874, and 521 to 922. The TraceDecay LCM shard ultimately contained 1,363 raw messages for a host transcript that originally had 216.

The issue was not the upstream OpenAI 429 itself. The 429 caused Hermes to retry compression and made the defect visible quickly. The root cause was TraceDecay active-message ingestion:

  • Host messages without an explicit id were assigned a deterministic ID containing their current array index.
  • TraceDecay replay messages carry a stable store_id, but not necessarily the original host id.
  • Compression inserts summary nodes and reorders the replay window.
  • On the next preflight, the same raw messages appeared at new indices and received new IDs.
  • TraceDecay therefore inserted duplicates on every compression attempt.
  • Derived replay entries carrying lcm_summary_node_id were also incorrectly ingested as new raw messages.

The fix resolves an ID-less replay message back to its original message ID using the fully scoped (provider, session_id, store_id) key before the index-based fallback is considered. Derived summary-node replay entries remain in the returned host transcript but are not inserted into raw history.

A regression test now performs the real sequence: ID-less preflight, compression with a generated summary and reordered raw tail, then replay ingestion. Before the fix, raw history grew from 4 rows to 7. After the fix, it remains exactly 4.

Correct Hermes provider identity

The generated Hermes plugin incorrectly used cursor as its LCM provider namespace. That made the current Hermes session invisible to provider-scoped hermes queries and mixed two distinct host identities.

The plugin now uses hermes. The generated-plugin check pins this contract. Existing cursor rows remain intact as historical data; newly loaded Hermes sessions use the correct namespace and start with clean host-scoped LCM state.

Live fact deletion and SQLite WAL stability

Live fact_store remove operations previously ran PRAGMA incremental_vacuum after every successful delete. The daemon caches multiple long-lived server/database handles for the same project shard. Running online vacuum while peer WAL/SHM connections remained open could poison the active connection state and produce:

database error: failed to apply pragmas: SQLite failure: disk I/O error

The database passed offline integrity checks, and restarting the daemon restored it immediately, confirming stale live connection/WAL state rather than file corruption.

Fact deletion now remains an immediate atomic transaction but leaves page reclamation to exclusive maintenance. The replacement regression opens a peer connection before repeated deletion, verifies deleted facts are visible from both the existing and a fresh peer, and verifies free pages remain available for later exclusive maintenance instead of compacting the live database.

CLI fallback correctness

One Hermes transcript invocation bypassed native deferred tools and invented unsupported per-key CLI flags such as context --max-tokens. The generated skill itself did not teach those flags, and the native plugin registration was healthy, but fallback guidance did not explicitly forbid guessing CLI flag names or enum values.

Shared agent guidance now states that fallback calls must use the MCP-equivalent JSON object through tracedecay tool <name> --args .... The Hermes skill includes an exact context example and documents the valid mode values (explore or plan) plus the actual keys (max_nodes, max_code_blocks). Generator tests pin those instructions.

Tool discovery and MCP decision

The installed Hermes plugin is correctly integrated with Hermes progressive discovery:

  • native plugin enabled;
  • memory provider and context engine registered;
  • bundled TraceDecay skill registered;
  • native TraceDecay schemas exposed to Hermes tool search;
  • plugin tool calls route through the installed TraceDecay binary using the same JSON contracts;
  • CLI remains a bounded fallback for hosts/children that do not receive a native schema.

MCP is intentionally not installed by this PR. It is unnecessary for Hermes and would duplicate the native plugin surface. This follows the user's final direction to keep Hermes native-plugin-only.

Validation

  • Memory suite: 52/52 passed.
  • LCM compression suite: 79/79 passed.
  • Agent suite: 503/503 passed.
  • Generated Hermes plugin checks: 39/39 passed.
  • cargo fmt --check: passed.
  • cargo check --all-targets: passed.
  • cargo clippy --all-targets -- -D warnings: passed.
  • git diff --check: passed.
  • Conventional commit validation: passed for all three commits.

Runtime follow-up

After merge and release, the update path must regenerate/install the Hermes plugin, restart the TraceDecay daemon and Hermes gateway so the new Python module and Rust binary are loaded, and manually repeat an ID-less compression replay to confirm raw row counts remain stable. Long-lived old tracedecay serve processes should be replaced only after the new binary is installed so active agent integrations do not retain v0.0.59 code.

@changeset-bot

changeset-bot Bot commented Jul 12, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: a67c1ec

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@ScriptedAlchemy ScriptedAlchemy merged commit 41b2bdd into master Jul 12, 2026
13 checks passed
@ScriptedAlchemy ScriptedAlchemy deleted the fix/defer-live-fact-vacuum branch July 12, 2026 03:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant