Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
cdc9aed
docs(perf): design text catch-up pipeline
ScriptedAlchemy Aug 24, 2026
018b5ff
docs(perf): plan text catch-up implementation
ScriptedAlchemy Aug 24, 2026
890ad94
docs(perf): tighten catch-up safety contracts
ScriptedAlchemy Aug 24, 2026
4d20381
chore(perf): configure hotpath mcp for repository
ScriptedAlchemy Aug 24, 2026
976ca2e
perf(index): batch verified lexical source pages
ScriptedAlchemy Aug 24, 2026
aad7637
perf(index): bulk commit lexical artifact pages
ScriptedAlchemy Aug 25, 2026
6a6253b
fix(ci): validate hotpath repository setup
ScriptedAlchemy Aug 25, 2026
749fc7b
feat(index): publish durable catch-up progress
ScriptedAlchemy Aug 25, 2026
7bc1746
Merge remote-tracking branch 'origin/codex/tracedecay-total-redesign-…
ScriptedAlchemy Aug 25, 2026
6ba1a76
fix(dashboard): retain current catch-up progress
ScriptedAlchemy Aug 25, 2026
9f36b91
fix(dashboard): order code index progress by incarnation
ScriptedAlchemy Aug 25, 2026
5a87150
fix(index): order progress by daemon incarnation
ScriptedAlchemy Aug 25, 2026
bfd750a
fix(dashboard): order remounted index progress
ScriptedAlchemy Aug 25, 2026
dc71489
perf(index): admit durable lexical page prefixes
ScriptedAlchemy Aug 25, 2026
f9c8700
perf(index): borrow admitted sealed decode bytes
ScriptedAlchemy Aug 25, 2026
ac6b60d
perf(query): defer lexical serving indexes
ScriptedAlchemy Aug 25, 2026
aeae244
fix(query): share repeated union bind values
ScriptedAlchemy Aug 25, 2026
d40e9be
perf(index): preserve immutable text catch-up
ScriptedAlchemy Aug 25, 2026
add3b50
perf(index): accelerate sealed layout scanning
ScriptedAlchemy Aug 25, 2026
3f8e905
perf(query): checkpoint setwise finalization
ScriptedAlchemy Aug 25, 2026
6dfc37d
feat(dashboard): publish ordered catch-up progress
ScriptedAlchemy Aug 25, 2026
022fcfa
test(dashboard): align catch-up progress fixture
ScriptedAlchemy Aug 25, 2026
5d142e1
fix(query): bound catch-up batch admission
ScriptedAlchemy Aug 25, 2026
1af4fd6
perf(hotpath): instrument sealed decode and artifact publish
ScriptedAlchemy Aug 25, 2026
b764985
fix(query): select exact prepared page prefix
ScriptedAlchemy Aug 25, 2026
2d2b90f
Merge remote-tracking branch 'origin/codex/tracedecay-total-redesign-…
ScriptedAlchemy Aug 25, 2026
cec6d23
feat(index): stream authenticated text metadata
ScriptedAlchemy Aug 25, 2026
7459022
perf(index): coalesce sealed generation writes
ScriptedAlchemy Aug 25, 2026
d8083a9
perf(hotpath): label code-index admission and extraction phases
ScriptedAlchemy Aug 25, 2026
9810e20
perf(privacy): batch credential keyword gates
ScriptedAlchemy Aug 25, 2026
272f40d
perf(graph): amortize bounded replay serialization
ScriptedAlchemy Aug 25, 2026
e78a806
test(index): share lexical fixture capture bytes
ScriptedAlchemy Aug 25, 2026
86af4a4
perf(index): share captured snapshot bytes
ScriptedAlchemy Aug 25, 2026
7b68427
perf(index): serve retained text before graph activation
ScriptedAlchemy Aug 25, 2026
7670a8b
perf(index): share physical generation artifacts
ScriptedAlchemy Aug 25, 2026
5bf8838
refactor(index): remove obsolete snapshot adjustment error
ScriptedAlchemy Aug 25, 2026
056750e
perf(hotpath): add bounded capture progress gauges
ScriptedAlchemy Aug 25, 2026
f9ce680
fix(index): bind text catch-up to active seal
ScriptedAlchemy Aug 25, 2026
73dc94b
perf(hotpath): instrument authoritative snapshot capture
ScriptedAlchemy Aug 25, 2026
72833e2
perf(hotpath): remove unused capture wrapper
ScriptedAlchemy Aug 25, 2026
12ea2c6
perf(hotpath): trace artifact publish and reconcile ttfq
ScriptedAlchemy Aug 25, 2026
595ef9f
perf(hotpath): trace sealed generation publication
ScriptedAlchemy Aug 25, 2026
9750d83
perf(hotpath): sample code-index file spans
ScriptedAlchemy Aug 25, 2026
41a66a4
fix(hotpath): name build queryability latency truthfully
ScriptedAlchemy Aug 25, 2026
4d77799
fix(hotpath): sample extraction digest phases
ScriptedAlchemy Aug 25, 2026
1fcc4f6
test(index): await incremental text serving
ScriptedAlchemy Aug 25, 2026
65a7e9a
perf(hotpath): bound capture progress cadence
ScriptedAlchemy Aug 25, 2026
fe431fe
fix(ci): restore test transport compilation
ScriptedAlchemy Aug 25, 2026
31d0c68
perf(query): localize ngram catch-up writes
ScriptedAlchemy Aug 25, 2026
f2aae13
fix(index): preserve graph-off text catch-up
ScriptedAlchemy Aug 25, 2026
24b59ee
fix(index): advance graph-off serving after source changes
ScriptedAlchemy Aug 25, 2026
fbc77c8
fix(index): preserve graph-off rebuild admission
ScriptedAlchemy Aug 25, 2026
07c8e4b
perf(query): parallelize SQLite index sorting
ScriptedAlchemy Aug 25, 2026
bbf3259
fix(index): serve graph-off queries from text artifacts
ScriptedAlchemy Aug 25, 2026
c731629
perf(query): widen bounded lexical catch-up
ScriptedAlchemy Aug 25, 2026
4445b5a
perf(query): shard lexical ngram postings
ScriptedAlchemy Aug 25, 2026
f76ec8d
fix(dashboard): keep polling until index freshness settles
ScriptedAlchemy Aug 25, 2026
636fd46
fix(index): satisfy callable query lint
ScriptedAlchemy Aug 25, 2026
229e827
perf(query): adopt page receipts for artifact verification
ScriptedAlchemy Aug 25, 2026
b981b2f
perf(query): widen lexical build reservation
ScriptedAlchemy Aug 25, 2026
7d36c38
test(query): cover net lexical build reservation
ScriptedAlchemy Aug 25, 2026
cdd591f
perf(query): order lexical term batch inserts
ScriptedAlchemy Aug 25, 2026
e6a5f5f
fix(semantic): build activation candidate in daemon
ScriptedAlchemy Aug 25, 2026
ae2d65b
fix(query): bound lexical term sort cancellation
ScriptedAlchemy Aug 25, 2026
01f9f74
fix(index): report graph-off text freshness
ScriptedAlchemy Aug 25, 2026
4686559
feat(index): persist text result display identity
ScriptedAlchemy Aug 25, 2026
6ba7b5a
perf(index): hydrate active text results from artifact
ScriptedAlchemy Aug 25, 2026
30128f3
perf(semantic): abstain before generation decode
ScriptedAlchemy Aug 25, 2026
fcc14f2
fix(index): decouple reconcile telemetry persistence
ScriptedAlchemy Aug 25, 2026
8601dc2
fix(git): resolve human PR branch refs
ScriptedAlchemy Aug 25, 2026
e09665a
fix(daemon): restore the evaluated semantic profile restart wait
ScriptedAlchemy Aug 25, 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: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
.DS_Store
.codegraph
.tracedecay
.mcp.json
!plugin/.mcp.json
.claude/settings.local.json
.cursor/
Expand Down
8 changes: 8 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"hotpath": {
"type": "http",
"url": "http://127.0.0.1:6771/mcp"
}
}
}
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

140 changes: 71 additions & 69 deletions crates/tracedecay-code-index/src/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ impl TreeSitterExtractor {
})
}

#[hotpath::measure]
pub(crate) fn extract_preparsed(
&self,
file: &ReceiptBoundCodeFileV1,
Expand All @@ -208,30 +207,32 @@ impl TreeSitterExtractor {
parsed_len: usize,
cancellation: &dyn ExtractionCancellation,
) -> Result<ExtractedCodeFileV1, ExtractionFailureV1> {
if cancellation.is_cancelled() {
return Err(ExtractionFailureV1::Cancelled);
}
let authority = file.authority().clone();
let file = file.validated_file();
validate_descriptor(file, descriptor)?;
let admitted_prefix = file
.sanitized_bytes
.get(..parsed_len)
.and_then(|bytes| std::str::from_utf8(bytes).ok());
if admitted_prefix.is_none() {
return Err(ExtractionFailureV1::ParseFailed {
detail: "retained parse prefix is not an admitted UTF-8 boundary".to_owned(),
});
}
finish_extraction(
authority,
file,
descriptor,
artifact,
parsed_len,
parsed_len < file.sanitized_bytes.len(),
cancellation,
)
crate::hotpath_observe::measure_hot_loop!("code_index.extract.incremental", {
if cancellation.is_cancelled() {
return Err(ExtractionFailureV1::Cancelled);
}
let authority = file.authority().clone();
let file = file.validated_file();
validate_descriptor(file, descriptor)?;
let admitted_prefix = file
.sanitized_bytes
.get(..parsed_len)
.and_then(|bytes| std::str::from_utf8(bytes).ok());
if admitted_prefix.is_none() {
return Err(ExtractionFailureV1::ParseFailed {
detail: "retained parse prefix is not an admitted UTF-8 boundary".to_owned(),
});
}
finish_extraction(
authority,
file,
descriptor,
artifact,
parsed_len,
parsed_len < file.sanitized_bytes.len(),
cancellation,
)
})
}

/// Typed evidence for one file whose bounded retained parse exceeded its
Expand Down Expand Up @@ -441,7 +442,7 @@ fn rows_digest(
.map(CanonicalUnresolvedRefRow::from)
.collect::<Vec<_>>();
let mut imports = artifact.imports.clone();
hotpath::measure_block!("code_index_rows_digest_sort", {
crate::hotpath_observe::measure_hot_loop!("code_index_rows_digest_sort", {
sort_canonical_rows(&mut nodes);
sort_canonical_rows(&mut edges);
sort_canonical_rows(&mut unresolved);
Expand All @@ -462,7 +463,7 @@ fn rows_digest(
unresolved_refs: Vec<CanonicalUnresolvedRefRow<'a>>,
}

hotpath::measure_block!(
crate::hotpath_observe::measure_hot_loop!(
"code_index_rows_digest_hash",
canonical_sha256(&RowsPayload {
separator: EXTRACTION_ROWS_SEPARATOR,
Expand All @@ -485,7 +486,7 @@ fn rows_digest(
pub(crate) fn parser_import_rows_digest(
imports: &[ExtractedImportEvidenceV1],
) -> Result<ManifestDigest, ExtractionFailureV1> {
hotpath::measure_block!("code_index_parser_import_rows_digest", {
crate::hotpath_observe::measure_hot_loop!("code_index_parser_import_rows_digest", {
let mut imports = imports.to_vec();
imports.sort();
canonical_sha256(&(PARSER_IMPORT_ROWS_DIGEST_SEPARATOR, imports.as_slice())).map_err(
Expand All @@ -497,55 +498,56 @@ pub(crate) fn parser_import_rows_digest(
}

impl LanguageExtractor for TreeSitterExtractor {
#[hotpath::measure]
fn extract(
&self,
file: &ReceiptBoundCodeFileV1,
descriptor: &LanguageDescriptorV1,
cancellation: &dyn ExtractionCancellation,
) -> Result<ExtractedCodeFileV1, ExtractionFailureV1> {
if cancellation.is_cancelled() {
return Err(ExtractionFailureV1::Cancelled);
}
let authority = file.authority().clone();
let file = file.validated_file();
validate_descriptor(file, descriptor)?;

let parser = self.resolve_parser(file, descriptor).ok_or({
ExtractionFailureV1::GrammarUnavailable {
language: descriptor.language.clone(),
crate::hotpath_observe::measure_hot_loop!("code_index.extract.full", {
if cancellation.is_cancelled() {
return Err(ExtractionFailureV1::Cancelled);
}
})?;
if canonical_language_id(parser.language_name()) != descriptor.language.as_str() {
return Err(ExtractionFailureV1::IncompatibleDescriptor {
detail: format!(
"descriptor {} resolved to a {} parser",
descriptor.language,
parser.language_name()
),
});
}

let source = std::str::from_utf8(&file.sanitized_bytes).map_err(|error| {
ExtractionFailureV1::ParseFailed {
detail: format!("sanitized bytes are not valid UTF-8: {error}"),
let authority = file.authority().clone();
let file = file.validated_file();
validate_descriptor(file, descriptor)?;

let parser = self.resolve_parser(file, descriptor).ok_or({
ExtractionFailureV1::GrammarUnavailable {
language: descriptor.language.clone(),
}
})?;
if canonical_language_id(parser.language_name()) != descriptor.language.as_str() {
return Err(ExtractionFailureV1::IncompatibleDescriptor {
detail: format!(
"descriptor {} resolved to a {} parser",
descriptor.language,
parser.language_name()
),
});
}
})?;
let parsed_len =
crate::chunks::snap_down(source, source.len().min(MAX_EXTRACTION_SOURCE_BYTES));
let extraction_source = &source[..parsed_len];
let source_was_capped = parsed_len < source.len();

let artifact = parser.extract_artifact(&file.file.logical_path, extraction_source);
finish_extraction(
authority,
file,
descriptor,
artifact,
parsed_len,
source_was_capped,
cancellation,
)

let source = std::str::from_utf8(&file.sanitized_bytes).map_err(|error| {
ExtractionFailureV1::ParseFailed {
detail: format!("sanitized bytes are not valid UTF-8: {error}"),
}
})?;
let parsed_len =
crate::chunks::snap_down(source, source.len().min(MAX_EXTRACTION_SOURCE_BYTES));
let extraction_source = &source[..parsed_len];
let source_was_capped = parsed_len < source.len();

let artifact = parser.extract_artifact(&file.file.logical_path, extraction_source);
finish_extraction(
authority,
file,
descriptor,
artifact,
parsed_len,
source_was_capped,
cancellation,
)
})
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/tracedecay-code-index/src/generations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ impl<R: LanguageRegistry> GenerationPlanner<R> {
/// Plan and seal one immutable generation while binding every inferred and
/// explicitly declared rebuild cause into its identity and publication
/// fence.
#[hotpath::measure]
#[hotpath::measure(label = "code_index.build.plan_full")]
pub fn plan_generation_with_invalidation(
&self,
snapshot: &ValidatedCodeSnapshotV1,
Expand Down Expand Up @@ -364,7 +364,7 @@ impl<R: LanguageRegistry> GenerationPlanner<R> {
/// quarantined corruption are not inferable from a sanitized snapshot,
/// so callers must declare them explicitly. Declared reasons are merged
/// with descriptor, sanitizer, chunker, and privacy incompatibilities.
#[hotpath::measure]
#[hotpath::measure(label = "code_index.build.plan_increment")]
pub fn plan_increment_with_invalidation(
&self,
prior_manifest: &CodeGenerationManifestV1,
Expand Down Expand Up @@ -681,7 +681,7 @@ pub enum GenerationJoinErrorV1 {
/// every eligible chunk names exactly one code generation and file
/// occurrence). Cross-generation documents or chunks, undeclared chunks, and
/// duplicates are typed rejections — never silently joined.
#[hotpath::measure]
#[hotpath::measure(label = "code_index.build.generation_join")]
pub fn join_chunks_to_generation(
generation: &CodeGenerationManifestV1,
document: &CodeSearchDocumentV1,
Expand Down
64 changes: 54 additions & 10 deletions crates/tracedecay-code-index/src/hotpath_observe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(feature = "hotpath")]
use std::time::Instant;

#[cfg(feature = "hotpath")]
#[cfg(any(feature = "hotpath", test))]
const HOT_LOOP_SAMPLE_PERIOD: u64 = 32;

#[cfg(feature = "hotpath")]
Expand All @@ -27,23 +27,46 @@ static WORKERS_ACTIVE: AtomicUsize = AtomicUsize::new(0);
#[cfg(feature = "hotpath")]
static WORKERS_POOL_COORDINATION: AtomicUsize = AtomicUsize::new(0);
#[cfg(feature = "hotpath")]
static GREP_FILE_SAMPLE: AtomicU64 = AtomicU64::new(0);
static HOT_LOOP_SAMPLE: AtomicU64 = AtomicU64::new(0);

#[cfg(feature = "hotpath")]
#[must_use]
#[inline(always)]
fn is_hot_loop_sample(sequence: u64) -> bool {
sequence.is_multiple_of(HOT_LOOP_SAMPLE_PERIOD)
}

#[must_use]
#[inline(always)]
pub(crate) fn sample_hot_loop() -> bool {
#[cfg(feature = "hotpath")]
{
GREP_FILE_SAMPLE
.fetch_add(1, Ordering::Relaxed)
.is_multiple_of(HOT_LOOP_SAMPLE_PERIOD)
is_hot_loop_sample(HOT_LOOP_SAMPLE.fetch_add(1, Ordering::Relaxed))
}
#[cfg(not(feature = "hotpath"))]
{
false
}
}

/// Measure one fixed-rate sample from a hot file loop.
///
/// The label must be a literal so callers cannot create path- or
/// generation-shaped cardinality. The disabled path still evaluates only the
/// work expression; its sampler is an inlined constant `false` with no atomic
/// or clock access.
macro_rules! measure_hot_loop {
($label:literal, $work:expr) => {{
if $crate::hotpath_observe::sample_hot_loop() {
hotpath::measure_block!($label, $work)
} else {
$work
}
}};
}

pub(crate) use measure_hot_loop;

#[cfg(any(feature = "hotpath", test))]
#[inline(always)]
fn decrement_if_positive(counter: &AtomicUsize) -> bool {
Expand Down Expand Up @@ -297,21 +320,26 @@ pub(crate) fn record_seal_bytes(bytes: u64) {
}
}

pub(crate) struct TtfqStart(#[cfg(feature = "hotpath")] Instant);
/// Start of one production-owner generation build. The matching observation
/// ends only after the immutable generation has been published and is
/// queryable through that owner; daemon scheduling/wake latency is measured
/// separately by the reconcile cadence receipt.
pub(crate) struct BuildToQueryableStart(#[cfg(feature = "hotpath")] Instant);

#[inline(always)]
pub(crate) fn start_ttfq() -> TtfqStart {
TtfqStart(
pub(crate) fn start_build_to_queryable() -> BuildToQueryableStart {
BuildToQueryableStart(
#[cfg(feature = "hotpath")]
Instant::now(),
)
}

#[inline(always)]
pub(crate) fn record_ttfq(started: TtfqStart) {
pub(crate) fn record_build_to_queryable(started: BuildToQueryableStart) {
#[cfg(feature = "hotpath")]
{
hotpath::gauge!("code_index_ttfq_micros").set(started.0.elapsed().as_micros() as f64);
hotpath::gauge!("code_index_build_to_queryable_micros")
.set(started.0.elapsed().as_micros() as f64);
}
#[cfg(not(feature = "hotpath"))]
{
Expand Down Expand Up @@ -347,6 +375,22 @@ pub(crate) fn record_rebuild_state(state: &'static str) {
mod tests {
use super::*;

#[cfg(feature = "hotpath")]
#[test]
fn hotpath_file_probe_cadence_uses_one_fixed_slot_per_period() {
let sampled = (0..(HOT_LOOP_SAMPLE_PERIOD * 2))
.filter(|sequence| is_hot_loop_sample(*sequence))
.collect::<Vec<_>>();

assert_eq!(sampled, vec![0, HOT_LOOP_SAMPLE_PERIOD]);
}

#[cfg(not(feature = "hotpath"))]
#[test]
fn hotpath_file_probe_sampler_is_dormant_without_the_feature() {
assert!((0..(HOT_LOOP_SAMPLE_PERIOD * 2)).all(|_| !sample_hot_loop()));
}

#[test]
fn pending_queue_decrements_when_each_worker_starts() {
let queue = PendingWorkQueue::new(3);
Expand Down
Loading
Loading