Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
73e6ccf
fix(cli): read glibc counters through mallinfo on the 2.31 baseline
ScriptedAlchemy Oct 18, 2026
9fdec8e
test(query): write historical fixtures without runfile permissions
ScriptedAlchemy Oct 18, 2026
fb85df8
fix(mcp): preserve live graph request cancellation
ScriptedAlchemy Oct 18, 2026
1022db4
test(dashboard): bound Bazel workers and isolate auth streams
ScriptedAlchemy Oct 18, 2026
f8c42c6
fix(hooks): preserve lifecycle evidence during replay
ScriptedAlchemy Oct 18, 2026
de2fa31
test(dashboard): reserve CPU capacity beyond Vitest workers
ScriptedAlchemy Oct 18, 2026
1ca3f8e
test(cli): preserve fixture modes and typed capacity retries
ScriptedAlchemy Oct 18, 2026
2971cac
test(sessions): distinguish exited zombies during shutdown
ScriptedAlchemy Oct 18, 2026
6914cc8
fix(memory): separate process and cgroup admission budgets
ScriptedAlchemy Oct 18, 2026
18513ff
fix(privacy): preserve UUID directory paths in entropy scans
ScriptedAlchemy Oct 18, 2026
be6a6e2
fix(hooks): honor lifecycle gating during ledger replay
ScriptedAlchemy Oct 18, 2026
8ca9c78
test(storage): use canonical writers and join fixture work
ScriptedAlchemy Oct 18, 2026
5beaa55
Merge PR #4336: process and shared memory admission
ScriptedAlchemy Oct 18, 2026
c7f5132
Merge PR #4333: live graph cancellation
ScriptedAlchemy Oct 18, 2026
875703f
Merge PR #4337: UUID path privacy
ScriptedAlchemy Oct 18, 2026
11a27bd
Merge PR #4334: bounded dashboard execution
ScriptedAlchemy Oct 18, 2026
b3b4050
Merge PR #4335: lifecycle-safe hook replay
ScriptedAlchemy Oct 18, 2026
e3df8d5
fix(build): share dashboard source copies across consumers
ScriptedAlchemy Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module(name = "tracedecay", version = "0.0.0")

bazel_dep(name = "platforms", version = "1.1.0")
bazel_dep(name = "bazel_skylib", version = "1.9.2")
bazel_dep(name = "bazel_lib", version = "3.7.0")
bazel_dep(name = "rules_python", version = "2.4.2")
bazel_dep(name = "rules_rust", version = "0.74.0")
# Rustc adds every dependency search directory to PATH on Windows; large
Expand Down
2 changes: 1 addition & 1 deletion crates/tracedecay-application/src/code_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ mod tests {
resident_bytes: bytes,
unreclaimable_bytes: bytes,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down
11 changes: 8 additions & 3 deletions crates/tracedecay-cli/tests/c_library_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ static MIMALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
const MIB: usize = 1024 * 1024;

/// Bytes glibc's arenas and its mmapped chunks hold for live allocations.
///
/// The hermetic toolchain links against glibc 2.31, which predates
/// `mallinfo2`. `mallinfo` reports the same counters as `int`, which this
/// test's few-MiB working set stays far below.
fn glibc_in_use() -> usize {
// SAFETY: `mallinfo2` only reads allocator statistics.
let info = unsafe { libc::mallinfo2() };
info.uordblks + info.hblkhd
// SAFETY: `mallinfo` only reads allocator statistics.
let info = unsafe { libc::mallinfo() };
usize::try_from(info.uordblks).expect("in-use arena bytes fit in int")
+ usize::try_from(info.hblkhd).expect("mmapped bytes fit in int")
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,23 +410,8 @@ impl CargoFixture {
let watched_input = directory.path().join("release-sha.txt");
std::fs::create_dir_all(&cargo_home).expect("fixture cargo home");
std::fs::write(&watched_input, ENV_SHA).expect("write watched input");
std::fs::create_dir_all(root.join("src")).expect("fixture source directory");
std::fs::create_dir_all(root.join("provenance/src"))
.expect("fixture build dependency source directory");

for relative in [
"Cargo.toml",
"Cargo.lock",
"build.rs",
"README.md",
"provenance/Cargo.toml",
"provenance/src/lib.rs",
] {
std::fs::copy(fixture.join(relative), root.join(relative))
.unwrap_or_else(|error| panic!("copy checked-in fixture {relative}: {error}"));
}
std::fs::copy(fixture.join("src/main.rs"), root.join("src/main.rs"))
.expect("copy checked-in fixture src/main.rs");
crate::common::fixture::copy_fixture_tree(&fixture, &root)
.expect("copy writable provenance fixture");

Self {
_directory: directory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,15 @@ fn uninstall_after_an_upgrade_removes_tracedecay_residue_and_keeps_unprovable_st
run_phase(&cli, id, &["install", "--agent", id], false);
}
strip_creation_records(&cli);
// Unproven directories must retain operator modes across update/uninstall,
// regardless of the umask that created them during the old installation.
for (relative, mode) in [(".cursor/plugins", 0o750), (".cursor/plugins/local", 0o710)] {
fs::set_permissions(
cli.home.path().join(relative),
fs::Permissions::from_mode(mode),
)
.unwrap();
}
deposit_legacy_cursor_extension(&cli);
let upgraded = home_snapshot(&cli);
for residue in [
Expand Down Expand Up @@ -503,8 +512,8 @@ fn uninstall_after_an_upgrade_removes_tracedecay_residue_and_keeps_unprovable_st
" + .cline/mcp.json: file 600 {}",
hex::encode(Sha256::digest(skeleton))
),
" + .cursor/plugins: dir 755".to_string(),
" + .cursor/plugins/local: dir 755".to_string(),
" + .cursor/plugins: dir 750".to_string(),
" + .cursor/plugins/local: dir 710".to_string(),
]
);
}
Expand Down
6 changes: 3 additions & 3 deletions crates/tracedecay-cli/tests/work_loop_journey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,13 +376,13 @@ impl ProductionDaemon {
(status, parsed)
}

/// Follows only the daemon's explicit same-request warming contract. A
/// terminal problem or malformed retry response is returned immediately,
/// Follows the daemon's explicit same-request warming and capacity retry
/// contract. A terminal problem or malformed retry response returns immediately,
/// so callers still prove their exact success or refusal below.
fn post_settled(&self, label: &str, route_path: &str, body: &Value) -> (u16, Value) {
poll_until(label, || {
let (status, answer) = self.post(route_path, body);
if status == 503
if matches!(status, 429 | 503)
&& answer["kind"] == "problem"
&& answer["value"]["problem"]["retryable"] == true
&& answer["value"]["problem"]["retry_scope"] == "same_request"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ fn measured_rss_pressure_refuses_worker_admission_and_readmits_as_it_falls() {
resident_bytes: unreclaimable_bytes,
unreclaimable_bytes,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down Expand Up @@ -577,7 +577,7 @@ fn a_refresh_after_cold_index_sizes_its_worker_slab_to_measured_headroom() {
resident_bytes: unreclaimable_bytes,
unreclaimable_bytes,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down Expand Up @@ -655,7 +655,7 @@ fn a_refresh_decodes_its_parent_before_planning_its_worker_slab() {
resident_bytes: 0,
unreclaimable_bytes: 0,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down Expand Up @@ -745,7 +745,7 @@ fn a_released_generation_decodes_again_only_once_its_bytes_fit_the_budget() {
resident_bytes: 0,
unreclaimable_bytes: 0,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down Expand Up @@ -829,7 +829,7 @@ fn a_decode_is_admitted_against_unreclaimable_bytes_not_clean_file_pages() {
resident_bytes: GIB,
unreclaimable_bytes: GIB,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
}));
let sampled = Arc::clone(&view);
let pressure = Arc::new(ResidentMemoryPressureV1::with_sampler(
Expand All @@ -853,7 +853,7 @@ fn a_decode_is_admitted_against_unreclaimable_bytes_not_clean_file_pages() {
resident_bytes: high_watermark - 1,
unreclaimable_bytes: 2 * GIB,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
};
let decoded = scheduler
.latest_complete()
Expand All @@ -879,7 +879,7 @@ fn a_decode_is_admitted_against_unreclaimable_bytes_not_clean_file_pages() {
resident_bytes: high_watermark - 1,
unreclaimable_bytes: high_watermark - 1,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
};
assert!(matches!(
scheduler.publication.load_active_shared(),
Expand Down Expand Up @@ -920,7 +920,7 @@ fn reconcile_stops_when_resident_memory_crosses_the_watermark() {
resident_bytes: unreclaimable_bytes,
unreclaimable_bytes,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn selected_graph_build_bound_reserves_transient_memory_and_retries_after_releas
resident_bytes: 0,
unreclaimable_bytes: 0,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ fn fixed_reading_authority() -> Arc<ProcessResidentMemoryV1> {
resident_bytes: 256 * 1024 * 1024,
unreclaimable_bytes: 256 * 1024 * 1024,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
};
Arc::new(ProcessResidentMemoryV1::with_pressure(
limit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2207,7 +2207,7 @@ fn text_artifact_ceilings_reserve_through_process_resident_memory() {
resident_bytes: live_bytes,
unreclaimable_bytes: live_bytes,
swapped_bytes: 0,
cgroup_committed_bytes: None,
cgroup_headroom_bytes: None,
})
}),
));
Expand Down
16 changes: 15 additions & 1 deletion crates/tracedecay-daemon-service/src/invocation/dispatch.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! The daemon invocation dispatcher: `DaemonInvocationService::invoke`.

use super::*;
use tracedecay_contracts::CancellationSignal;
use tracedecay_runtime_core::cancellation::CancellationToken;
use tracedecay_runtime_core::path_safety::canonical_existing_identity;
use tracedecay_tool_catalog::ApplicationSurfaceOperation;
Expand Down Expand Up @@ -785,13 +786,26 @@ impl DaemonInvocationService {
let Some(owner) = graph_tool_owner else {
return missing_registered_owner_problem(publication, request_id);
};
let signal = match self.request_cancellations.signal(&request_id, &request_cancellation) {
Some(signal) => signal,
None => match CancellationSignal::active(cancellation.token_id.as_str()) {
Ok(signal) => signal,
Err(_) => return DaemonInvocationResponse::problem(
request_id,
DaemonInvocationProblem::InvalidRequest,
),
},
};
if let CancellationState::Cancelled { requested_at } = cancellation.state {
signal.cancel(requested_at);
}
Box::pin(execute_graph_tool(
request_id,
owner,
surface_operation,
arguments,
deadline,
cancellation,
signal,
request_cancellation,
))
.await
Expand Down
13 changes: 3 additions & 10 deletions crates/tracedecay-daemon-service/src/invocation/graph_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ use std::sync::Arc;
use serde_json::{Map, Value};
use tracedecay_contracts::graph_tool::GraphToolCompletionV1;
use tracedecay_contracts::{
ApplicationProblem, CancellationContext, CancellationSignal, CancellationState, Deadline,
RequestId, ResolvedScope, now_micros,
ApplicationProblem, CancellationSignal, Deadline, RequestId, ResolvedScope, now_micros,
};
use tracedecay_daemon_protocol::{
DaemonInvocationOutcome, DaemonInvocationProblem, DaemonInvocationResponse,
Expand Down Expand Up @@ -92,21 +91,15 @@ pub(super) async fn execute_graph_tool(
operation: ApplicationSurfaceOperation,
arguments: Map<String, Value>,
deadline: Deadline,
cancellation: CancellationContext,
signal: CancellationSignal,
request_cancellation: tracedecay_runtime_core::cancellation::CancellationToken,
) -> DaemonInvocationResponse {
let (Ok(typed_request_id), Ok(signal)) = (
RequestId::new(request_id.clone()),
CancellationSignal::active(cancellation.token_id.as_str()),
) else {
let Ok(typed_request_id) = RequestId::new(request_id.clone()) else {
return DaemonInvocationResponse::problem(
request_id,
DaemonInvocationProblem::InvalidRequest,
);
};
if let CancellationState::Cancelled { requested_at } = &cancellation.state {
signal.cancel(*requested_at);
}
let execution = owner.port.execute(GraphToolInvocationV1 {
operation,
arguments,
Expand Down
Loading
Loading