fix: harden runtime routing and ci#453
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: a85f505 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d50588d76e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This follow-up hardens the live TraceDecay/Hermes integration after the v0.0.58 rollout and addresses defects found by dogfooding real Hermes, Codex, Cursor, automation, analytics, and service logs. It keeps Windows coverage enabled while preventing superseded PR work and unsafe release cancellation.
Why this is needed
The live audit found four distinct correctness gaps:
tracedecay analytics diagnosticsread session counts from legacyglobal.db.session_messages. Session data is now project/user sharded, so diagnostics reported zero messages despite more than 900,000 healthy LCM raw messages.tracedecay:tracedecayto the agent. In addition, the live Hermes profile'sautotool-search threshold did not activate for the large-context model, leaving 137 schemas/193 KB visible.The CI/release audit also found that the Windows summary used
always(), which can keep a superseded run alive, release PR integrity lacked PR-scoped cancellation, release-plz serialization began only at the second job, stable release publication was cancelable, and beta release publication was not serialized.Changes
Session and project correlation
code_projectscanonical/display roots.project_aliases, including linked worktrees.git-common-dir:because transcript attribution requires real paths.This affects both Cursor and Hermes projectless catch-up because they share the same registered-root guard. Transport remains irrelevant: Telegram and non-Telegram Hermes sessions use the same session/workspace attribution path.
Sharded analytics diagnostics
sessions.db.--all, deduplicate and sum all registered project session shards plususer-sessions.db.Autonomous memory curator
context.llm_review.messagescopy and retain only operational review metadata around it.input_too_largefailure as scheduler-retryable on a later rebuilt request, while keeping classification of the currently oversized request permanent so identical immediate retries are still prevented.validate_then_apply; no dry-run gate was introduced.Hermes discovery
tracedecay:tracedecayskill through the first-turn code/project nudge soskill_viewcan load it.Live profile validation additionally enabled Hermes progressive tool discovery (
tools.tool_search.enabled=on). Offline stock-Hermes assembly then reduced the model-visible surface and successfully found TraceDecay callers/impact tools through the bridge;skill_view("tracedecay:tracedecay")loaded the generated skill.CI and release safety
always()predicate with!cancelled()while leaving the Windows build and all shards enabled.cancel-in-progress: trueto release PR integrity.Test isolation
--test-threads=1.Live rollout evidence
tracedecay doctor: database integrity OK; 32 watched projects, none degraded.fact not found.tracedecay_callers,tracedecay_impact, and related tools.skill_view("tracedecay:tracedecay")succeeded.Verification
cargo test --test hermes_suite: 66 passed.cargo test --test automation_runner_test: 160 passed.cargo test --test session_suite -- --test-threads=1: 222 passed.cargo check --all-targets: passed.cargo clippy --all-targets -- -D warnings: passed.cargo fmt --all -- --check: passed.bash tests/release_workflow_contract_test.sh: passed.actionlinton all changed workflows: passed.git diff --check: passed.Release note
Includes a patch changeset for the next release. No user memory, project databases, blocked manifests, or Hermes-owned skill directories are deleted or rewritten by this PR.
Follow-up hardening and platform verification
The curator change does not add a blunt byte truncation layer. It serializes the review evidence once instead of duplicating the same corpus in two prompt sections; the existing cluster bounds then keep the rebuilt production request below the backend ceiling while preserving the full bounded evidence set.
The v0.0.58 rollout already supplied Hermes runtime-cwd routing, stable Hermes session IDs, and explicit user-versus-project memory scope. This PR extends transport-agnostic historical catch-up through modern registered roots and worktree aliases. Telegram is only one Hermes transport and is never used as a memory-scope key.
Portable fixtures now create independent Git roots, write matching project identity only where eligibility is intended, canonicalize temporary paths for macOS /var to /private/var behavior, refresh the reviewed generated-Hermes asset hash, and restore both structured-backfill process switches after daemon-gate assertions. The final local workspace run passed 4,655 tests with 2 intentional skips.
The CI design follows GitHub concurrency semantics: pull-request work shares a PR-number group and newer commits cancel superseded runs. Aggregate jobs use !cancelled() rather than always() so cancellation can drain. Publication workflows serialize mutations with cancel-in-progress false. Stable and beta manual rebuilds now require an explicit tag and share the same concurrency identity as automatic publication; beta dispatch validates that the target is an existing prerelease and checks out that tag. Windows remains enabled and exercised, but is not made a merge prerequisite.
After merge, release-plz will publish the patch. The rollout is not considered complete until tracedecay update installs it, stale TraceDecay/Hermes runtimes are restarted, and live diagnostics, project/user routing, Hermes discovery, autonomous curation, and log canaries are repeated against the installed binary.
Telegram transcript and live-log follow-up
The live Telegram DM session
20260711_131044_4e9b777fsupplied a decisive mixed-scope case. Hermes keeps that long-lived DM row unpinned (cwd,git_repo_root, andgit_branchare null), but the TraceDecay turn correlator inspects the current turn’s terminal calls. The user message “Find tracedecay ptoject. List open PRs on it find local repo” produced terminal calls withworkdir=/fast/projects/tracedecay; project-scoped TraceDecay transcript search returns that exact message from the TraceDecay shard. Thus a general Telegram conversation can remain user-scoped overall while repository turns are attributed to the correct project. Transport is not the scope key.That same transcript exposed two additional defects. First, projectless context compression forgot to attach
storage_scope=usertotracedecay_lcm_compress, so a 371,447-token general chat attempted project discovery and returned an unchanged replay instead of compacting the user LCM store. Second, project discovery usedtracedecay_active_projectagainst speculative process paths such as/home/zack,/, and/home/zack/.hermes/hermes-agent, creating daemon errors and allowing a nested Hermes-owned path past the exact-home guard.The fix routes projectless compression explicitly to the profile-level user session store. Project correlation now resolves candidates through the global project registry, understands canonical roots and worktree aliases, and does not open a project shard merely to test an unregistered path. Both generated transport and plugin routing reject the Hermes home and every descendant. Bare transport calls no longer infer a project from the plugin process cwd; routed host wrappers supply real session or tool workspace evidence. Regression coverage reproduces projectless compression, registry alias resolution, Hermes-descendant rejection, and legacy-pin isolation. The generated Hermes suite now passes 68/68, with Clippy and formatting clean.
Canonical user history and multi-project turn correlation
The final correlation model deliberately separates host-session identity from per-turn repository attribution. Every completed Hermes turn is written once to the profile-level user session store as the canonical conversation. TraceDecay then scans only that turn—from its last user message through the assistant tool calls/results—collects every explicit project selector,
cwd,workdir, and terminalcd, resolves those candidates through the registry and worktree aliases, and projects the same user/assistant pair into every distinct project shard touched by the turn.Canonical and project projections use identical stable
(provider, message_id)identities. No global fact table or session-wide project pin is introduced, and no schema migration is required. The canonical projection recordsassociated_project_roots; project searches find the same user message in each relevant shard, while user-scope search retains the complete Telegram/CLI/Desktop conversation. A later general-chat turn does not inherit earlier project attribution because candidate collection is bounded to the current turn, andself.project_rootis not mutated by fan-out.Historical Hermes catch-up now follows the same rule. The existing project sweeper already fans one historical turn into every matching destination; user catch-up now retains all turns rather than excluding project-attributed turns. Its cursor version advances from
user-turn-v1touser-turn-v2, forcing one idempotent backfill so already-advanced installations recover previously omitted canonical user messages.Each successful canonical/project write emits its matching
turnCompletedandturnIngestedreceipt in that scope. This closes the earlier gap where a terminal receipt could exist in an earlier project touched by a multi-project turn but only the last project received ingestion readiness. Tests cover canonical metadata preservation, identical IDs across user and project stores, two-project fan-out, no session rebinding, historical canonical recovery, worktree alias resolution, and Hermes-home descendant rejection. Final bounded aggregate verification passed 4,659/4,659 tests with 2 intentional skips using eight local test threads; all affected Hermes, transcript, agent, MCP, formatting, Clippy, workflow-contract, and actionlint checks pass.Local development dogfood installation
This PR also adds the missing first-class local-development deployment path requested during live verification.
cargo dogfoodbuilds the current checkout as a locked release binary, copies it out of Cargo’s mutabletarget/tree to~/.local/lib/tracedecay/dogfood/tracedecay, and atomically replaces~/.local/bin/tracedecay. This prevents later rebuilds, cleans, worktree removal, or Cargo file locks from invalidating the executable used by active agents.After staging, the command explicitly removes Cargo’s hermetic
TRACEDECAY_DATA_DIR=target/test-profile/.tracedecayandTRACEDECAY_DISABLE_GLOBAL_DB=1environment before invoking the installed binary. It then runs the canonical hiddenpost-updatelifecycle, which quiesces and refreshes the managed daemon, regenerates plugin assets, refreshes every tracked host integration, performs the health pass, updates install markers, and restarts the prior daemon state. It finally verifies daemon status, doctor output, and binary version. It never invokes published-release upgrade, so an unmerged checkout cannot be silently replaced by the latest GitHub release.The command is exposed as the Cargo alias
cargo dogfoodand implemented byscripts/dogfood.sh. Its isolated contract test uses a fake Cargo executable, fake built binary, temporary HOME, custom target directory, and action log to prove the build arguments, stable stage copy, global executable copy, post-update call, daemon status, doctor, and version verification without touching the real user profile. CI runs this shell contract in the Release Version Drift job.A repo-local
dogfooding-tracedecayskill is installed for both Codex and Claude. The twoSKILL.mdfiles are byte-identical and teach agents to usecargo dogfoodrather thancargo runortracedecay upgrade, verify the live global runtime, inspect host/service logs, preserve in-flight worktrees, and rerun deployment after source changes. Contract tests validate the Codex skill frontmatter, host mirror parity, required stable paths, isolation warning, verification commands, and release-upgrade prohibition.Dogfood implementation correction and live result
The first attempted Cargo alias used Git-style
!scripts/dogfood.sh; live execution correctly rejected it because Cargo aliases do not support shell escapes. A second launcher prototype exposed that starting a nested Cargo build fromcargo runcan wait on the outer Cargo build lock. Both defects were caught before merge and replaced by the final lock-safe design:.cargo/config.tomlmapscargo dogfoodtocargo run --quiet --release --bin tracedecay -- dogfood; the hidden developer subcommand receives the already-built release executable throughcurrent_exe, invokes the staging script withTRACEDECAY_DOGFOOD_SOURCE_BINARY, and therefore performs no nested Cargo invocation. Direct script use still performs its own locked release build.The final command was exercised against the real user profile. It built PR head code, staged and atomically installed it, completed the normal post-update lifecycle, refreshed Claude/Codex/Cursor/Hermes and all other tracked integrations, restarted the systemd user daemon, verified a connectable daemon socket, ran doctor, and printed the installed version.
target/release/tracedecay,~/.local/lib/tracedecay/dogfood/tracedecay, and~/.local/bin/tracedecaywere byte-identical after deployment. Focused verification after the launcher correction passed 2,095/2,095 tests pluscargo check --all-targets, formatting, shell syntax, isolated dogfood contract, skill validation, mirror parity, and diff checks.The health pass found no actionable installation failures. It preserved three pre-existing blocked store manifests lacking repository identity/enrollment and reported one historical Cursor MCP connection failure whose host requires a Cursor reload/toggle; neither warning was introduced by the dogfood deployment.