feat: TraceDecay V2 delivery (PR8–PR13) + daemon performance, memory, and reliability overhaul - #707
feat: TraceDecay V2 delivery (PR8–PR13) + daemon performance, memory, and reliability overhaul#707ScriptedAlchemy wants to merge 3404 commits into
Conversation
🦋 Changeset detectedLatest commit: ebe2706 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 |
|
Post-reopen correction pushed in a23f86a: source-neutral background reconcile no longer advances the scheduler epoch and cancel in-flight text activation; mounted hook overflow uses the explicit invalidating path. Evidence: RED reproduced 0/1, GREEN 1/1 for ordinary_background_reconcile_does_not_supersede_in_flight_text_work; cargo check --lib --locked passed. |
💡 Codex Reviewtracedecay/.github/workflows/release.yml Lines 408 to 411 in fc20c4f For Linux targets, this archive now contains tracedecay/release-please-config.json Lines 22 to 25 in fc20c4f The new npm publication job derives its version from the packed tracedecay/dashboard/src/workspaces/delivery/DeliveryPage.tsx Lines 80 to 82 in fc20c4f When the scope bar selects a project other than the active project, this query keeps the same cache key and continues fetching the unprefixed active-project route. The dashboard already provides tracedecay/src/tracedecay/lifecycle/registry.rs Lines 118 to 122 in fc20c4f When AGENTS.md reference: AGENTS.md:L159-L161 tracedecay/plugin/cursor-native-extension/src/extension.ts Lines 187 to 189 in fc20c4f At activation or language-client restart, ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
fix(clippy): clear the workspace clippy failures on #707
Removing the re-export shims left their module doc comments orphaned in `context` and `graph`. The rest are pre-existing lints that only fire under `--all-features`, which compiles the `test-transport` support surface as non-test code: - the registered-test-server constructor gets the file's existing explicit `expect_used` allow, since `lib.rs` denies it only outside `cfg(test)`; - `http_application_registry` is read by the `cfg(test)` capacity journey and only reads as dead under `test-transport` alone, so the allow is gated to `not(test)` rather than renamed to a discard; - the hotpath cadence helpers keep `#[inline(always)]` with an explicit allow, preserving the author's intent instead of silently downgrading it. The `daemon_suite` restart wait is now the original helper recovered from the PR #707 head rather than a reconstruction: it additionally proves the runtime readiness receipt authorizes the exact configuration the SDK selected.
The relocation fix that anchored this test above the package allocated a `PathBuf` only to hand out a reference, which `-D warnings` rejects as `unnecessary_to_owned` and which failed the Clippy gate on #707. `validate_requested_workload` takes `&Path`, and `CARGO_MANIFEST_DIR` is a literal, so `Path::new` yields a `&'static Path` with no allocation and no temporary to borrow from.
|
#733 landed Clippy-red. Helper branch (not merged, shared checkout untouched):
Clears the #733 Clippy denials:
Adopt when you want: I will not land this on #707. |
|
Clippy helper is now on the Codex worktrees (still not landed on this PR head):
Same change as |
|
Isolated post-#721 verification (worktree Green (non-vacuous) on merge
Not green
Clippy helper remains on this tree at |
Ports the missing pieces of commit b1e41b712 ("fix(build): land the
batching commit's missing consumers") onto #707: HookCompletedReadinessDistributions
moved into tracedecay-agent-hosts with pub(crate) fields, so
input_rows_processed, input_rows_dropped_at_cap, and events_considered
are no longer reachable outside the crate. Adds the three public
accessors.
source_event and input_rows_received (also added by the source commit)
are not ported: nothing on this branch reads them through an accessor
today - the root-crate benchmark still compares via
serde_json::to_value(&readiness_distributions)["field"], which does
not need them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
5d8f2a1 to
c7fcf3f
Compare
…d6ed chore(vendor): stacked vendor-only PR for #707 — generated vendor churn, land first
…rules Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
`stock_host_registration_evidence` was an 18-arm `match` building near-identical `HostRegistrationEvidenceV1` rows per host. Replace it with one `const HOST_REGISTRATIONS: &[HostRegistrationDescriptor]` table (host, route, evidence_ref, starts_analyzer) written through a small local `macro_rules!`, and implement the function as a filter over the table that projects each row's state from the canonical capability matrix via `HostRegistrationRouteV1::capability()`, which stays the only route -> capability mapping. Output is byte-identical for every host: 57 rows across 18 hosts, CLI row first (consumers index `routes[0]`). The pre-change rows were captured from the `match` into `fixtures/stock_host_registration_evidence.json` and a test asserts every host's projected rows equal that fixture. The completeness test now iterates the table and every `HostKindV1` variant. Closes #1089
The freshness witness reduced every source candidate to (path, len, mtime) and treated an equal signature as proof that the retained generation was source-current. A same-length rewrite whose mtime was preserved (rsync -a, cp --preserve, touch -d, restore tools) therefore never reconciled and the stale generation served indefinitely, on the live ladder, across restart, and for explicitly admitted ignored sources. The stat signature is now a negative cache only. Unequal metadata still skips straight to reconcile without reading a byte. Equal metadata is followed by re-deriving each candidate's canonical content digest through the same bounded read + sanitize + digest path capture uses and comparing it against the generation's own sealed file manifest (SanitizedCodeSnapshotV1::files). The fence, the query ladder, restart admission, the retained text path, and the empty-serving seat all consult that manifest; the on-disk witness format is unchanged and keeps naming the generation whose manifest is the authority. A tracked file whose raw bytes disagree with a clean-tree generation may still be exactly HEAD's blob once git's clean filters (core.autocrlf, eol, ident, drivers) are applied, so disputed tracked files are re-checked through the repository's filter pipeline before they disprove currency; untracked and admitted sources have no blob to be sealed from. Closes #1071.
The scheduler and registry docs still called the freshness ladder a stat signature proof. Name the two layers as they now behave: the stat sweep as the negative cache and the sealed file digests as the currency proof.
`kiro_hooks_capture_prompt_boundary_and_type_post_tool_use_unsupported` expects the Kiro `userPromptSubmit` callback to spool its PromptBoundary envelope when no daemon answers. ee3b8a8 (merged through a919de7) made the Codex and Kiro prompt callbacks answer `{}` and exit 0 without dispatching when the profile has no installed identity record, and the enrollment fixture only pinned the repository identity and published the hook binding — it never installed the profile, so the hook stayed quiet and nothing reached the spool. An enrolled project always belongs to an installed profile in production, so `enroll_native_capture_project` now installs the identity through the canonical `profile_identity::load_or_create` authority before creating the project store. `cargo test -p tracedecay-cli --test core_cli_suite -- tool_daemon_test::kiro_hooks_capture_prompt_boundary_and_type_post_tool_use_unsupported --exact` → 1 passed.
With the `hotpath` feature every `#[hotpath::measure]` async fn lays out as 13 nested layout_of frames (the fn future, `measure_async[_future]`, the `InstrumentedFuture`/caller-scope wrapper and the body block, each behind `MaybeUninit`/`ManuallyDrop`/`MaybeDangling`) instead of 4, so the registered schema admission chain overflowed rustc's 128-deep query limit wherever a concrete admission future was laid out: `attach_registered_inner`'s boxed block in tracedecay-store-runtime (the `--all-features` CLI build), and the `HostAdmissionTestRuntimeV1` / `RegisteredGlobalDbTestRuntime` harness roots in the tracedecay-global-db, -session-temporal-store and -session-memory lib tests. The expanding child was the same in all four crates (full query stack via `-Ztreat-err-as-bug`): `admit_and_attach_with_operation_task_owner` -> `converge_attached_registered_schema` -> `converge_registered_schema_on` -> `ensure_authority_invariants` -> `authority_invariant_step` -> `validate_projection_authority_chunk` -> `validate_projection_authority_suffix_pages` -> `verify_native_source_supersession` -> `resolve_output_projection` -> `message_projection` -> `derive_projection_with_alias` -> `derive_projection_with_alias_from_generation` -> `durable_projection_disposition` -> engine query. The sibling admission path through `ensure_attached_registered_schema` -> `classify_registered_schema_admission` -> `require_admissible_session_temporal_schema` -> contract validation -> `read_table_metadata` sat between 105 and 112 frames on its own. The three phase owners now run their state machine behind `Box::pin` so the admission futures embed only a pointer and rustc lays each phase out as its own root: `ensure_authority_invariants` (the resumable audit), `classify_registered_schema_admission` (read-only authority classification) and `install_registered_schema_stages` (the admission transaction). Signatures, measure labels, error mapping and ordering are unchanged; the deepest chain in the global-db lib test drops from >128 to at most 104 frames. Closes #1068.
`lsp_disconnect_expiry_settles_unacknowledged_outbound_as_dropped` ran its whole body under `start_paused = true` so it could advance past `LSP_SESSION_TTL_MS`. Its final step drains the delivery settlement recorder, whose durable writes go through the SQLite writer. b501f51 moved that writer from `spawn_blocking` — which inhibits tokio's paused-clock auto-advance while in flight — to awaiting an `async_channel` acknowledgement from the writer thread. The paused runtime no longer sees any pending work while the write is outstanding, auto-advances straight to the recorder's shutdown timer, and the drain reports `delivery_settlement_recorder_shutdown_deadline` although the write completes moments later. Pause the clock only around the TTL advance and resume it before the drain, so the settlement runs against real time like every other LSP delivery test. `cargo test -p tracedecay --lib --features test-helpers -- daemon::invocation_tests::lsp_tests::lsp_disconnect_expiry_settles_unacknowledged_outbound_as_dropped --exact` → 1 passed.
`the_hook_runtime_handle_answers_through_root_adapters` (914bde7) compared the resolved `StoreLayout::project_root` against the canonicalized temp root while handing the runtime the raw `tempdir()` path. The layout keeps the caller's spelling of the root, so on macOS — where temp roots live behind the `/var` -> `/private/var` symlink — the assertion compared two spellings of one directory and failed. Linux temp roots are already canonical, which is why the Linux run stayed green. Canonicalize the fixture root before use, the way the other daemon fixtures already do (617949c, 0664edf), and compare against that same path.
`write_hook_output` retains a delivery receipt before answering the host, and its spool writer lock is shared with the daemon's replay consumer. The a919de7 merge resolution switched that open from a non-waiting `open` to `open_until(started + synchronous budget)`, anchoring the lock wait at the hook process's start. The synchronous budget is 100 ms; several response hooks legitimately spend longer than that before they reach the write — the Kiro prompt callback runs a bounded transcript catch-up (1.5 s budget) and the Codex PostCompact callback awaits the daemon's compaction journey. For them the deadline was already expired on arrival, so `lock_until` refused even an uncontended lock, `write_hook_output` returned false before writing stdout, and the hook exited 1 with no output for the host. Anchor the bounded wait at the write itself: one synchronous budget to acquire the shared lock, whatever the body cost. The `started` parameter no longer has a reader, so drop it and the bindings that only fed it. Fixes `codex_compaction::codex_post_compact_hook_commits_app_server_summary_through_daemon_effect` (deterministic: the compaction always outlasts the budget) and the `hook-kiro-prompt-submit exited with Some(1)` attempt of `hook_replay_test::replayed_provider_hooks_record_attributed_rows_and_bridge_to_analytics_events` (timing-dependent on the same deadline).
ffa01d3 routed the capture-only native callbacks (and Claude's retired `preToolUse`) through `record_native_capture_invoked`, so every hook the host fires records one attributed `hook_invoked` row whatever its capture outcome — 14 of the 27 native commands had been firing silently. The a919de7 merge took `hook_replay_test` from the other lane (ee3b8a8), whose `emits_timing_rows` still expected zero rows from those callbacks, while production kept ffa01d3's recorder; the replay then found the Claude `preToolUse` row production now writes and failed. Restate the test to ffa01d3's contract: exactly one row per replay, and every one of them bridged into `analytics_events`. `cargo test -p tracedecay --features test-helpers --test hooks_lsp_suite -- hook_replay_test::replayed_provider_hooks_record_attributed_rows_and_bridge_to_analytics_events --exact` → 1 passed (with the receipt-wait fix).
9bc7ded (#899) made a selector-bound `fact_store get` report the scope of the project whose store actually answered instead of the calling session's admitted project. 2f17bc8 (merged through a919de7) carried an older local copy of `get_selected_project_fact` that asserts the admitted project id on `scope.project_id`, so the acceptance journey failed with project B's id where it expected project A's. Assert the selected project's id, keeping the `assert_ne!` so the restatement is only satisfied by a genuinely restated scope. `cargo test -p tracedecay --features test-helpers --test runtime_acceptance_suite -- grafeo_restart_acceptance::memory_relation_graph_survives_physical_daemon_restart_and_isolates_profile_and_projects --exact` → 1 passed.
`native_stream_projection_replaces_retained_effects_and_rebuilds_without_duplicates` (2f17bc8, merged through a919de7) seeds a projection alias row named `retained.cline.message`. The global database authority audit has always admitted only `consolidated/<lineage>/<unaliased message id>` aliases (`validate_alias_binding`), and it runs on every open; after the native source transition transfers that alias to the successor and the test reopens the profile runtime, the audit refused the fixture with "projection alias is not an eligible consolidation output binding". Seed an alias production could have produced — `consolidated/retained/` over the canonical fixture's `record.projection-cline.0` — and assert on it. `cargo test -p tracedecay --features test-helpers --test session_suite -- observation_projection::source_transition::native_stream_projection_replaces_retained_effects_and_rebuilds_without_duplicates --exact` → 1 passed.
069ca84 (#890/#892) cut the bundled skills down to domain guidance and deferred tool schemas to the live catalog. It also dropped every mention of the mutating tool families, so `registered_tools_are_referenced_by_the_plugin_bundle` found 61 registered tools — Work, Workflow, Context Scout control, configuration mutation, source edits, fact writes, session refresh, native integration, worktree removal — that no skill, rule, command, or agent in the Cursor bundle points an agent at, which is the silent-tool-family state that guard exists to catch. Name each tool once, inline where its skill already describes the operation (`managing-work`, `managing-workflows`, `editing-safely`, `project-memory`, `reviewing-changes`, `discovering-tracedecay`, `managing-session-context`). Names are routing hints, not the argument catalogs #892 removed; the bodies still defer arguments to the live schemas. `generated_skill_mirrors_session_context_retrieval_contract` is restated to the same split: the repository skill and the Hermes skill must both route to the retrieval operations and preserve the wire fields (`next_cursor`, `coverage`, `anchors`, `needs_synthesis`), while argument defaults and worked guidance (`provider=all`, `temporal_mode=…`, `begin`/`status`/`cancel`, …) stay a requirement of the Hermes template, which is the full manual its host installs and which 069ca84 did not touch. `cargo test -p tracedecay --lib --features test-helpers -- mcp::tools::plugin_conformance_tests::registered_tools_are_referenced_by_the_plugin_bundle mcp::tools::plugin_conformance_tests::plugin_tool_mentions_resolve_to_registered_tools mcp::tools::plugin_conformance_tests::readme_mcp_allowlist_matches_read_only_tools --exact` → 3 passed. `cargo test -p tracedecay --features test-helpers --test hermes_suite -- lcm_bridge::generated_skill_mirrors_session_context_retrieval_contract --exact` → 1 passed.
…ign-plan-reopened
The serving-readiness test asserted that a source hint makes the query ladder report a required reconcile. After e92e602 the ladder judges movement from source truth only, because the hint already posted its own pass and a query that re-reported it escalated the targeted hint pass into an observed-change rescan. The production invariant the test guards is that the seated proof is refused until that pass revalidates it, which the fence still enforces through the epoch; assert both halves explicitly. The semantic availability journey read only the first page of a truncated tracedecay_search answer; reassemble the handle through offset / next_offset / has_more exactly as the CLI and the bootstrap harness do.
|
CI red-suite triage (run 34168826002) — landed at 04da312 ( All 11 non-lane-owned failures are green with
The remainder were tests that lost their contract in the merge — Excluded: the two store-runtime publication tests (fixed under #1066) and |
`InvocationConnectionLease` settled every drop with one boolean: a successful request returned its stream to idle, and any other outcome discarded the stream *and* cleared the whole idle pool. One reset socket therefore forced every concurrent caller to reconnect and re-handshake even when the daemon behind the pool had not changed. Replace the boolean with an explicit `LeaseDisposition`: - `Return` — the request settled on this stream; it goes back to idle. - `DiscardOne` — the default. Write/read/protocol failures, cancellation, timeouts, indeterminate effects and unacknowledged deliveries retire only their own stream. Possibly desynchronized sockets still never return to idle. - `InvalidatePool` — only on evidence the daemon generation changed: the daemon refused this client's handshake (revision or credential rotation), or the authority liveness probe reports the record that named this endpoint is no longer current (restart). Production connections discovered through the authority record always carry that probe, so a real restart still drains the pool on the first failure. Two hotpath gauges (`…pool.discarded_total`, `…pool.invalidated_total`) make reconnect storms attributable to one or the other. The former `transport_failure_purges_other_idle_connections_before_reconnect` test asserted the old over-invalidation without any authority evidence; it now models a restart with a rotated authority record. New tests prove a request-local failure leaves the other idle stream reusable (and reused without a new accept), and that a handshake refusal drains the pool. Closes #1041.
`QuiescedDaemonLifecycle`'s `Drop` ran `let _ = self.restore();`. When maintenance code unwound before an explicit `finish*`, a failed fallback restore vanished: the managed daemon could be left stopped with nothing naming it. The same fallback also re-ran a restore whose failure an explicit `finish*` had already returned to its caller, silently spending a second readiness window on the same failure. Replace the `restored: bool` with a `RestoreSettlement`: - `Owed` — restore not yet successful; `Drop` is the fallback. - `Complete` — set only after a restore actually succeeds, or when the caller explicitly waives it (`finish_without_restore`). - `FailureReturned` — an explicit finish attempted the restore and returned the typed error; `Drop` neither retries nor re-reports it. `Drop` now attempts the restore only while `Owed` and, if it fails, emits one `tracing::error!` carrying the captured prior state, the expected daemon version, whether the exclusive lease was still owned, and the typed restore error. It never panics, so an in-flight unwind is not turned into an abort. Explicit `finish`, `finish_with_state`, `finish_after_update` and the combined operation+restore paths keep returning their errors directly. Tests capture the crate's `tracing` output: an unwind after quiesce with a failing systemd `start` attempts the restore exactly once and logs one structured error with those fields; an explicit `finish` that fails returns the error, attempts no second restore, and logs nothing; a completed finish leaves `Drop` silent. Closes #1042.
…esign-plan-reopened
Replacement review for #421 after its accidental merge was reverted from master in 52a9aab. This commit has the exact tree of #421 head d4c67d4. Do not merge until explicitly authorized.
Issues this PR fixes
Refs #753 (source-identity + restart journey tests landed on branch at eae9328; keep draft until full product journey/CI)
Refs #792 (journey acceptance pending)
Refs #837 (journey acceptance pending)
Refs #838 (journey acceptance pending)
Refs #855 (journey acceptance pending)
Fixes #862
Fixes #861
Fixes #810
Fixes #845
Fixes #856
Fixes #853
Fixes #799
Fixes #836
Fixes #830
Partially addressed here, tracked to completion on their own issues: #852, #800, #863, #843, #842, #848.
🤖 Generated with Claude Code
#887 dead-surface deletion inventory
build_statecompatibility wrapper was deleted; the liveget_gc_metasuppression was removed.clean_c_comment/clean_c_doc_commentare retained because feat: TraceDecay V2 delivery (PR8–PR13) + daemon performance, memory, and reliability overhaul #707 now has production callers in C, C++, GLSL, Go, and Objective-C extractors.cargo check --workspace --all-targets;cargo clippy --workspace --all-targets -- -D warnings; both pass on the integrated branch.#888/#890/#891/#892 workflow cleanup
using-tracedecaybootstrap was deleted, detailed mechanics moved to live tool help, and unique safety/domain rules remain narrowly routed.no_skill_needed, and keep only actual host size/syntax limits.