Skip to content

refactor: remove host and wire-protocol legacy support - #4613

Closed
ScriptedAlchemy wants to merge 9 commits into
masterfrom
refactor/remove-legacy-lane-b
Closed

ScriptedAlchemy wants to merge 9 commits into
masterfrom
refactor/remove-legacy-lane-b

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

Why

tracedecay keeps no legacy or backward-compatibility code. This PR removes inventory units U12–U18, which cover host compatibility and the wire protocol. One commit per unit; each commit body lists the items removed, the callers migrated, the tests deleted, and its upgrade impact. 125 files changed, +986 / −2,687.

Units

Unit Commit Removes
U12 refactor(hermes): drop older-host compatibility paths Hermes probes and aliases kept for older Hermes hosts (L013, L052, L053, L062, L064, L068)
U13 refactor(capture): drop older Codex, Claude and Kiro shapes Codex user_message records, Kiro .chat transcripts and other older transcript shapes (L057, L058, L063, L067). Fixtures move to item_completed/UserMessage
U14 refactor(automation): drop pre-lease task lock coordination The pid-file automation lock kept for daemons that predate leases (L056)
U15 refactor(daemon): refuse clients from a different build Handshake version-skew tolerance, serde(default) handshake fields, and preface-less broker clients (L060, L071, L079, L081). A client of another build gets the typed daemon_protocol_revision_skew refusal
U16 refactor(mcp): drop alias methods and compatibility fields The bare initialized method, the lcm_grep since/until aliases, and tool-surface aliases (L016, L061, L070, L076, L080). The SDK, the dashboard schema and the ChatGPT-extension embed are regenerated
U17 refactor(contracts): require fields daemons always serialize serde(default) on daemon status and storage responses (L069, L073, L075, L077)
U18 refactor(domain): drop pre-commit_index git index decoding Decoding of git-index previews and receipts stored before commit_index (L072)

Upgrade impact

  • A CLI, proxy or long-running tracedecay serve from a different build is refused by a new daemon. Restart it after upgrading.
  • A new CLI can't decode status from an old daemon until that daemon restarts.
  • Older Hermes hosts, Codex user_message records and Kiro .chat transcripts are no longer ingested. Rows already ingested are kept.
  • Hosts must send notifications/initialized instead of the bare initialized. lcm_grep callers must use the current time-range fields.
  • Git-index previews and receipts stored before commit_index no longer verify.
  • During an upgrade, stop the old daemon before starting the new one. The pid-file lock that kept two daemons from running the same automation task is gone.

Notes for review

  • U15, build identity: it reuses the existing versions_name_same_build. That function treats a version without build metadata as the same identity as any commit of that release, which tracedecay update relies on when it compares a release tag with the binary it installed. When both sides name a commit, the commits must match.
  • U15, fixture runtime: the test fixture product runtime now reports the bare release version, so a test process can drive the daemon binary it spawns.
  • U15, readiness probes: daemon_reachable and daemon_socket_connectable now send the caller's build version. The readiness probe treats a typed refusal as a running daemon of another build.
  • U13, fixtures: about 60 Codex fixtures move to the current shape through one helper per crate.

Verification

  • Each unit: bazel build --config=clippy and bazel test on the touched crates. U16–U18 also ran contracts:check and check:embedded.
  • After rebasing on current master: gen_builds --check is current, and the regenerated ChatGPT embed passes check:embedded.
  • Local suite runs had failures from machine load that passed on rerun.
  • The four remote_cli_test HTTPS cases also fail on master.
  • hermes_plugin_unit_check.py and hermes_stock_check.py were only syntax-checked; uv and PyYAML aren't available locally. hermes_suite passes.

🤖 Generated with Claude Code


Devin Review

@changeset-bot

changeset-bot Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8b1a4c4

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

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

expected_version: &str,
) -> Vec<StoreResetRequiredV1> {
if !daemon_control::daemon_reachable(profile) {
if !daemon_control::daemon_reachable(profile, crate::product_runtime::PRODUCT_BUILD_VERSION) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Post-update store resets go unreported

After an upgrade installs a different build, restored_daemon_pending_resets probes with the old CLI version. The restored daemon refuses that handshake, so update reports completion without listing stores requiring reset.

Learn more

The update flow runs in the old CLI process while replacing the daemon binary. Its expected_version argument is the version of the newly installed binary, passed by run_update_flow. The new daemon refuses a readiness handshake advertising the old CLI build, and daemon_reachable only returns true for an initialize answer or a typed refusal. A typed refusal ordinarily counts as reachable, but the subsequent reset census uses the installed version; using that same version for both probes gives a consistent check and avoids mismatches when the old and new builds advertise the same release with different commit metadata.

Example: An old CLI at 1.0.0+aaaa installs a daemon at 1.0.0+bbbb with one store in reset-required state. The reachability probe advertises +aaaa; the new daemon refuses it, and the reset census is skipped instead of reporting the pending reset.

Recommended fix: Pass expected_version to daemon_reachable, matching the version already passed to daemon_reset_required_stores. Verify the post-update journey with same-release builds carrying different commit metadata.

Suggested change
if !daemon_control::daemon_reachable(profile, crate::product_runtime::PRODUCT_BUILD_VERSION) {
if !daemon_control::daemon_reachable(profile, expected_version) {

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

ScriptedAlchemy and others added 9 commits October 29, 2026 04:11
Items removed: L013/L068 (fixed-action fact_* tool aliases and the
fact_type->category translation in the plugin), L052 (hermes_cli.config
get_hermes_home fallback), L053 (register_context_engine capability
gate), L062 (state.db column probing and no-active frontier variant),
L064 (wrapper compatibility API forwarders, /capabilities, _proxy).

Callers migrated: skill.md and the stock/unit check scripts use
fact_store(action=...) with category; the Hermes ctx test stubs implement
register_context_engine; the sessions fixtures build state.db from one
current-schema DDL (TEST_STATE_DB_SCHEMA_SQL); docs/dashboard.md no longer
describes the /legacy frontend proxy.

Tests deleted: fact_add/fact_type alias assertions (unit check, stock
check), the LegacyCtx registration case, the minimal legacy state.db
fixture and its pagination/seek-plan halves, and
sweep_reads_legacy_stores_without_active_or_reasoning_columns.

Upgrade impact: Hermes must provide hermes_constants, register_context_engine
and the current state.db sessions/messages columns. Older builds fail plugin
load, and their state.db is refused with a typed missing-columns error
instead of being ingested. Agents must call fact_store(action=...);
fact_add/fact_search/... and the wrapper's /holographic, /lcm, /graph,
/savings, /analytics, /automation and /capabilities routes no longer exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Items removed: L057 (Codex event_msg user_message records), L058
(id-less Codex response goal context; Claude API-error placeholders
recognised by the synthetic model without isApiErrorMessage), L063 (Kiro
<workspace-hash>/<execution-id>.chat layout and its two .chat discovery
scans), L067 (render-codex-hook-inputs user_message branch and the
retired static tracedecay hint classification). The Cursor epoch-ms
createdAt handling stays: Cursor's store keeps old composers, so it is
current data.

Callers migrated: every Codex rollout fixture in the sessions,
host-admission, transcript-ingest, mcp, runtime and transport suites,
the two benches and tool_sweep now write item_completed/UserMessage via
one helper per crate; Kiro fixtures use extensionless execution files.

Tests deleted: kiro_legacy_chat_populates_searchable_messages and
write_legacy_chat, the content-addressed session_rewrite case, the older
synthetic-model placeholder case, test_legacy_user_message_remains_supported.

Upgrade impact: Codex rollouts with event_msg user_message prompts, Codex
response goal-context items without an id, and Kiro .chat transcripts are
no longer ingested; rows already ingested are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Item removed: L056. AutomationTaskLock now holds only the <key>.lease
file. Deleted the <key>.lock.lock publication-coordination lease,
retire_pre_lease_owner, PreLeaseOwner, read_pre_lease_owner,
parse_unique_lock_field, recorded_owner_was_reused,
unverifiable_pre_lease_owner and MAX_PRE_LEASE_TASK_LOCK_BYTES.
process_state, foreign_process_is_dead and append_lock_path stay: other
callers use them.

Callers migrated: the scheduler prefilter and memory-curator runner tests
that held a lock by writing a pid file now hold a real lease through
AutomationTaskLock::try_acquire(_keyed).

Tests deleted: the old/new process participant harness and
old_and_new_processes_exclude_publication_and_execution_until_release,
the five pre_lease_* unit tests plus reaped_pid, the pid-file reclaim
cases in automation_runner_test (and the liveness child helpers), and
memory_curator_runner_recovers_stale_scheduler_lock_file. The
cancellation, symlink and lifecycle tests lose their lock.lock halves.

Upgrade impact: an older daemon that is still running no longer excludes
the new daemon, so both can run the same automation task at once during
a mixed-version upgrade. Stop the old daemon before starting the new
one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Items removed: L060, L071, L079, L081. The daemon no longer serves a
version-skewed client with a warning. Every handshake is checked once,
before anything is routed: a client from another build, a client that
reports no version, or one with a non-conforming instance id gets one
typed unsupported_revision refusal frame, and the connection closes.

Removed: the six #[serde(default)] handshake fields (a handshake missing
any of them is refused as unsupported_revision), the empty-version
no-skew rule, the per-client admission bypass for invalid instance ids,
the skew log (client_version_skew_to_log, log_client_version_skew,
logged_client_version_skews), the proxy-side skew warning
(daemon_version_skew_warning_for_request), refuse_enrollment_from_another_build
(subsumed by the handshake check), and the mixed-version docs. The
saturation path now requires the auth preface and applies the same
refusal.

Callers migrated: daemon_reachable and daemon_socket_connectable take the
caller's build version instead of daemon-control's own crate version, and
the readiness probe reads a typed refusal frame as a running daemon of
another version. Integration suites build handshakes through one helper
that names only the release; the fixture runtime reports its release
without a commit so a test process matches the daemon binary it spawns.
Fixture client ids are conforming.

Tests deleted: the legacy handshake decode cases, the version-skew log
test, the empty-version skew case, per-client admission for legacy
clients, the enrollment-from-another-build test, the legacy listChanged
half of the proxy metadata test, the proxy skew-warning assertion in
mcp_cli_serve_test. Added: skewed-client refusal at the handshake and
over the live daemon, every-field-required, probe refusal case.

Upgrade impact: an older CLI or long-lived `tracedecay serve` talking to a
newer daemon, or the reverse, is refused with unsupported_revision
(daemon_protocol_revision_skew) instead of being served with a warning.
Restart MCP hosts and any running `tracedecay serve` after upgrading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Items removed: L016 (since/until aliases on tracedecay_lcm_grep, in the
MCP catalog schema, LcmGrepRequestV1, the retrieval merge, and the Hermes
lcm_grep schema), L061/L076 (bare `initialized` MCP method), L070
(AffectedResultV1.affected_tests and AffectedRankingMetadataV1.
compatibility_field; count and touched files now derive from
ranked_tests), L080 (authority_audit_error mirroring the typed reason; the
key now carries only the observed detail, null otherwise). message_search
and sessions_for keep their own since/until, and LSP `initialized` is
untouched.

Callers migrated: the lcm_grep MCP test and the preserved-profile
journey send start_time; the affected tests and the golden JSON assert
ranked_tests; the SDK client fixture drops the removed fields.
Regenerated in this commit: sdks/typescript/src/operations.ts and
plugin/chatgpt-extension/embedded/server.mjs (contracts:check and
check:embedded pass). The regeneration also picks up the StatusHookReplayV1
`waiting` variant that master's generated SDK was missing.

Tests deleted: the "compatibility list must remain exhaustive and
path-sorted" assertion. Added: classify_mcp_method("initialized") is
Unknown.

Upgrade impact: lcm_grep requests that send since/until are rejected;
use start_time/end_time. A host that sends a bare `initialized` gets
method-not-found; hosts must send notifications/initialized.
tracedecay_affected no longer returns affected_tests or
ranking_metadata.compatibility_field; read ranked_tests/recommended_tests.
Regenerate SDK clients. Doctor readers use authority_audit_reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Items removed: L069 (CodeIndexWorktreeFreshnessV1.rebuild_in_flight
default), L073 (source_role default on CompactCandidate, FusedCandidate,
ExactLaneEvidence and LexicalLaneEvidence, plus the
LexicalRouteReceiptV1.decision default), L075 (the StorageReport and
StorageReportCoverage serde defaults for size_coverage, root_state,
unavailable_entry_count, graph_container, graph_replay_pool,
code_generation_retention_availability, user_sessions_db_bytes,
unregistered_size, unregistered_count_is_lower_bound, and the
digest_verified default plus digest_verified_default), L077
(ReaderPoolSnapshot.snapshot_admissions default). Defaults paired with
skip_serializing_if (full_profile_size, footprint, reason) stay.

Regenerated: dashboard/codegen/schemas/dashboard-contracts.schema.json,
sdks/typescript/src/operations.ts and plugin/chatgpt-extension/embedded/
server.mjs (contracts:check and check:embedded pass).

Tests deleted: the older-response half of
graph_serving_readiness_is_additive_for_older_daemon_responses (the test
keeps the terminal-verdict cases under a new name) and
exact_lane_evidence_treats_missing_source_role_as_production_other.

Upgrade impact: a new CLI reading a storage report or freshness payload
from an older daemon fails to decode it. Restart the daemon after
upgrading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Item removed: L072. The git index preview input, preview and receipt wire
structs no longer accept commit_intent, commit_intent_digest or
created_commit (deny_unknown_fields now rejects them), the digest
material no longer carries the always-null commit_intent_digest and
created_commit keys, and final_snapshot_captured is required instead of
defaulting to true. default_true stays: other crates use it.

Tests deleted: records_stored_before_commit_index_removal_still_decode and
tests/fixtures/git_index_legacy/ (three JSON fixtures). Added:
removed_commit_fields_and_missing_receipt_flags_are_refused, which builds
current records and proves the removed fields and the missing flag are
refused.

Upgrade impact: dropping the null keys changes the digest of every
preview, preview input and receipt, so stored pending git-index previews
and stored receipts written by an earlier build fail digest verification
and are refused with the existing typed digest-mismatch error. Re-create
pending git-index previews after upgrading. No migration code was added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
U17 (fb73388) made FusedCandidate.source_role required, but two
tracedecay-mcp unit fixtures still decoded candidates from JSON without it,
so route_evidence_is_attached_only_when_additional_routes_ran and
markdown_search_trims_the_weak_tail_but_json_returns_every_row panicked
with `missing field source_role` on Linux fleet CI. The fixtures now carry
the current shape. No other fixture in the repo decodes a FusedCandidate
from JSON (rg for "utility_micros" outside generated schemas).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
U16 (c912814) removed the bare `initialized` MCP alias, so
classify_mcp_method("initialized") is Unknown and the request is no
longer reserved control traffic. mcp_discovery_requests_are_reserved_control_traffic
still asserted the alias was reserved and failed in //crates/tracedecay:unit_test
on Linux fleet CI. The test now covers only notifications/initialized.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Combined into #4623 with lanes A, B and C, merged with --no-ff so this branch's commits land unchanged; that PR's merge commit marks this one merged.

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Landed on master through #4623 (merge commit f193d1d). git cherry shows all nine lane-B commits as patch-equivalent on master except U16, which differs only in the regenerated plugin/chatgpt-extension/embedded/server.mjs bundle. GitHub didn't auto-mark this PR merged because the branch was rebased after the integration branch merged it. Closing.

@ScriptedAlchemy
ScriptedAlchemy deleted the refactor/remove-legacy-lane-b branch October 30, 2026 06:27
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