tensor-grep 1.65.2__tar.gz → 1.65.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tensor-grep might be problematic. Click here for more details.

Files changed (132) hide show
  1. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/PKG-INFO +1 -1
  2. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/pyproject.toml +3 -1
  3. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/Cargo.lock +3 -3
  4. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/Cargo.toml +3 -1
  5. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_sidecar_ipc.rs +100 -14
  6. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/ast_backend.py +19 -0
  7. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/LICENSE +0 -0
  8. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/NOTICE +0 -0
  9. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/README.md +0 -0
  10. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/deny.toml +0 -0
  11. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/rust-toolchain.toml +0 -0
  12. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/backend_ast.rs +0 -0
  13. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/backend_ast_workflow.rs +0 -0
  14. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/backend_cpu.rs +0 -0
  15. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/bin/tg_search_fast.rs +0 -0
  16. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/cli.rs +0 -0
  17. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/crossover.rs +0 -0
  18. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/editor_plane.rs +0 -0
  19. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/gpu_native.rs +0 -0
  20. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/index.rs +0 -0
  21. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/lib.rs +0 -0
  22. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/main.rs +0 -0
  23. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/mmap_arrow.rs +0 -0
  24. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/native_search.rs +0 -0
  25. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/python_sidecar.rs +0 -0
  26. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/rg_passthrough.rs +0 -0
  27. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/routing.rs +0 -0
  28. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/src/runtime_paths.rs +0 -0
  29. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_ast_backend.rs +0 -0
  30. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_ast_cache.rs +0 -0
  31. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_ast_grep_embed.rs +0 -0
  32. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_ast_rewrite.rs +0 -0
  33. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_audit_manifest_symlink_unix.rs +0 -0
  34. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_gpu_native.rs +0 -0
  35. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_gpu_native_error_handling.rs +0 -0
  36. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_gpu_native_graphs.rs +0 -0
  37. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_gpu_native_integration.rs +0 -0
  38. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_gpu_native_long_lines.rs +0 -0
  39. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_gpu_native_streams.rs +0 -0
  40. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_index.rs +0 -0
  41. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_mmap_arrow.rs +0 -0
  42. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_native_search.rs +0 -0
  43. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_output.rs +0 -0
  44. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_public_native_cli_parity.rs +0 -0
  45. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_python_bootstrap.rs +0 -0
  46. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_release_profile.rs +0 -0
  47. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_replace.rs +0 -0
  48. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_resident_worker.rs +0 -0
  49. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_routing.rs +0 -0
  50. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_runtime_path_resolution.rs +0 -0
  51. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_schema_compat.rs +0 -0
  52. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_search.rs +0 -0
  53. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_search_golden.rs +0 -0
  54. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/rust_core/tests/test_smart_routing.rs +0 -0
  55. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/__init__.py +0 -0
  56. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/__main__.py +0 -0
  57. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/__init__.py +0 -0
  58. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/ast_wrapper_backend.py +0 -0
  59. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/base.py +0 -0
  60. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/cpu_backend.py +0 -0
  61. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/cudf_backend.py +0 -0
  62. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/cybert_backend.py +0 -0
  63. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/ripgrep_backend.py +0 -0
  64. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/rust_backend.py +0 -0
  65. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/stringzilla_backend.py +0 -0
  66. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/backends/torch_backend.py +0 -0
  67. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/__init__.py +0 -0
  68. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/_index_lock.py +0 -0
  69. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/agent_capsule.py +0 -0
  70. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/apply_policy.py +0 -0
  71. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/ast_workflows.py +0 -0
  72. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/audit_manifest.py +0 -0
  73. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/bootstrap.py +0 -0
  74. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/checkpoint_store.py +0 -0
  75. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/codemap.py +0 -0
  76. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/commands.py +0 -0
  77. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/docs_coverage.py +0 -0
  78. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/dogfood.py +0 -0
  79. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/evidence_receipt.py +0 -0
  80. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/formatters/__init__.py +0 -0
  81. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/formatters/base.py +0 -0
  82. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/formatters/csv_fmt.py +0 -0
  83. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/formatters/json_fmt.py +0 -0
  84. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/formatters/ripgrep_fmt.py +0 -0
  85. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/formatters/table_fmt.py +0 -0
  86. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/inventory.py +0 -0
  87. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/lang_go.py +0 -0
  88. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/lang_registry.py +0 -0
  89. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/lsp_external_provider.py +0 -0
  90. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/lsp_provider_setup.py +0 -0
  91. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/lsp_server.py +0 -0
  92. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/main.py +0 -0
  93. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/mcp_server.py +0 -0
  94. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/orient_capsule.py +0 -0
  95. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/progress.py +0 -0
  96. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/repo_map.py +0 -0
  97. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/rg_contract.py +0 -0
  98. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/rule_packs.py +0 -0
  99. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/runtime_paths.py +0 -0
  100. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/scan_guardrails.py +0 -0
  101. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/session_daemon.py +0 -0
  102. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/session_store.py +0 -0
  103. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/cli/subprocess_policy.py +0 -0
  104. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/__init__.py +0 -0
  105. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/config.py +0 -0
  106. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/hardware/__init__.py +0 -0
  107. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/hardware/device_detect.py +0 -0
  108. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/hardware/device_inventory.py +0 -0
  109. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/hardware/memory_manager.py +0 -0
  110. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/observability.py +0 -0
  111. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/pipeline.py +0 -0
  112. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/query_analyzer.py +0 -0
  113. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/registration_check.py +0 -0
  114. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/reranker.py +0 -0
  115. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/result.py +0 -0
  116. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_bm25.py +0 -0
  117. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_chunker.py +0 -0
  118. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_dense.py +0 -0
  119. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_fusion.py +0 -0
  120. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_late.py +0 -0
  121. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_lexical.py +0 -0
  122. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/retrieval_scoring.py +0 -0
  123. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/core/semantic_index.py +0 -0
  124. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/__init__.py +0 -0
  125. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/base.py +0 -0
  126. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/directory_scanner.py +0 -0
  127. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/reader_cudf.py +0 -0
  128. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/reader_dstorage.py +0 -0
  129. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/reader_fallback.py +0 -0
  130. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/io/reader_kvikio.py +0 -0
  131. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/perf_guard.py +0 -0
  132. {tensor_grep-1.65.2 → tensor_grep-1.65.4}/src/tensor_grep/sidecar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tensor-grep
3
- Version: 1.65.2
3
+ Version: 1.65.4
4
4
  Requires-Dist: typer>=0.12,<0.26
5
5
  Requires-Dist: rich>=13.0
6
6
  Requires-Dist: mcp>=1.2.0
@@ -492,12 +492,14 @@ version_variables = [
492
492
 
493
493
 
494
494
 
495
+
496
+
495
497
 
496
498
 
497
499
 
498
500
  [project]
499
501
  name = "tensor-grep"
500
- version = "1.65.2"
502
+ version = "1.65.4"
501
503
  description = "High-performance grep-compatible CLI with Rust, GPU, and AST/NLP routing"
502
504
  readme = { file = "rust_core/README.md", content-type = "text/markdown" }
503
505
  requires-python = ">=3.11"
@@ -1579,7 +1579,7 @@ dependencies = [
1579
1579
 
1580
1580
  [[package]]
1581
1581
  name = "tensor_grep_rs"
1582
- version = "1.65.2"
1582
+ version = "1.65.4"
1583
1583
  dependencies = [
1584
1584
  "aho-corasick",
1585
1585
  "anyhow",
@@ -1677,9 +1677,9 @@ dependencies = [
1677
1677
 
1678
1678
  [[package]]
1679
1679
  name = "tree-sitter"
1680
- version = "0.26.10"
1680
+ version = "0.26.11"
1681
1681
  source = "registry+https://github.com/rust-lang/crates.io-index"
1682
- checksum = "3c343ed63e3f5c64d1acdecb5d2c13d4e169cb5fde0052106ebaa6c6f27f9e55"
1682
+ checksum = "af1c71c1c4cc0920b20d6b0f6572e7682cd07a6a2faec71067a31fa394c586df"
1683
1683
  dependencies = [
1684
1684
  "cc",
1685
1685
  "regex",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tensor_grep_rs"
3
- version = "1.65.2"
3
+ version = "1.65.4"
4
4
  edition = "2021"
5
5
  description = "Rust core engine for tensor-grep"
6
6
  license = "Apache-2.0"
@@ -400,6 +400,8 @@ path = "src/bin/tg_search_fast.rs"
400
400
 
401
401
 
402
402
 
403
+
404
+
403
405
 
404
406
 
405
407
 
@@ -532,6 +532,41 @@ fn write_wedged_python_script(dir: &Path) -> PathBuf {
532
532
  }
533
533
  }
534
534
 
535
+ #[cfg(not(feature = "cuda"))]
536
+ // #145: `test_help_probe_timeout_env_override_falls_back_fast_with_wedged_python` (below) and
537
+ // `test_help_probe_default_timeout_recovers_with_enriched_fallback_when_python_is_wedged` (further
538
+ // below) both drive `tg --help` against the SAME wedged-Python mechanism and measure wall-clock --
539
+ // the single most directly identifiable source of mutual contention for either test's timing
540
+ // assertion if `cargo test`'s default thread-parallelism happens to schedule them at the same time.
541
+ // This lock makes that specific pair mutually exclusive. It cannot (from a single test file) also
542
+ // exclude the ~14 OTHER subprocess-spawning tests in this binary or unrelated CI-runner load; see
543
+ // `HELP_PROBE_TRIALS` and the widened gap in the override-honored test below for how the timing
544
+ // assertion itself stays robust to that residual noise.
545
+ static HELP_PROBE_TIMING_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
546
+
547
+ #[cfg(not(feature = "cuda"))]
548
+ fn lock_help_probe_timing() -> std::sync::MutexGuard<'static, ()> {
549
+ // Recover from poisoning instead of propagating it: if an EARLIER test panicked on its own
550
+ // assertion while holding this lock, unwrapping a PoisonError here would replace that test's
551
+ // real failure message with an unrelated "lock poisoned" panic in this one. The lock only
552
+ // provides mutual exclusion for timing purposes, not shared data integrity, so recovering is safe.
553
+ HELP_PROBE_TIMING_LOCK
554
+ .lock()
555
+ .unwrap_or_else(|poisoned| poisoned.into_inner())
556
+ }
557
+
558
+ #[cfg(not(feature = "cuda"))]
559
+ const HELP_PROBE_SHORT_OVERRIDE_MS: &str = "250";
560
+ #[cfg(not(feature = "cuda"))]
561
+ const HELP_PROBE_LONG_OVERRIDE_MS: &str = "6000";
562
+ #[cfg(not(feature = "cuda"))]
563
+ const HELP_PROBE_MIN_GAP: Duration = Duration::from_millis(2500);
564
+ #[cfg(not(feature = "cuda"))]
565
+ // Each variant is measured this many times and the FASTEST run is kept -- see the doc comment on
566
+ // `min_wedged_help_probe` for why min-of-N is the right reducer for a noise source that only ever
567
+ // adds latency.
568
+ const HELP_PROBE_TRIALS: u32 = 2;
569
+
535
570
  #[cfg(not(feature = "cuda"))]
536
571
  fn run_wedged_help_probe(wedge_script: &Path, probe_timeout_ms: &str) -> Duration {
537
572
  // Run `tg --help` against a wedged (never-responding) Python with the given help-probe timeout
@@ -547,8 +582,12 @@ fn run_wedged_help_probe(wedge_script: &Path, probe_timeout_ms: &str) -> Duratio
547
582
 
548
583
  let started = Instant::now();
549
584
  // Generous outer hang-guard: guards only against a truly-hung command, NOT the timing assertion
550
- // (the short-vs-long comparison lives in the caller). 30s tolerates heavy CI runner starvation.
551
- let output = run_with_timeout(tg, Duration::from_secs(30));
585
+ // (the short-vs-long comparison lives in the caller). #145: raised 30s->60s to keep a comparable
586
+ // safety margin above the widened long-side probe override (3000ms -> 6000ms); the wedged Python
587
+ // itself only ever sleeps ~20s (write_wedged_python_script), so in practice this ceiling is not
588
+ // expected to fire even under heavy contention -- it exists purely so a genuinely broken
589
+ // kill-on-timeout regression fails as a bounded panic instead of hanging the runner.
590
+ let output = run_with_timeout(tg, Duration::from_secs(60));
552
591
  let elapsed = started.elapsed();
553
592
 
554
593
  assert!(
@@ -564,6 +603,23 @@ fn run_wedged_help_probe(wedge_script: &Path, probe_timeout_ms: &str) -> Duratio
564
603
  elapsed
565
604
  }
566
605
 
606
+ #[cfg(not(feature = "cuda"))]
607
+ // #145: race `probe_timeout_ms` `trials` times against the wedged Python and keep the FASTEST
608
+ // (minimum) elapsed. CI subprocess-spawn/scheduler contention only ever ADDS latency -- it never
609
+ // makes a run finish faster than its true uncontended cost -- so the minimum across independent
610
+ // trials is a statistically principled lower-bound estimate, and a single unlucky trial (one
611
+ // thread-scheduling hiccup, one antivirus scan of a freshly-written EXE) no longer decides the
612
+ // result the way a single-shot measurement does. This does NOT weaken the regression check: if
613
+ // TG_HELP_PROBE_TIMEOUT_MS is genuinely ignored, EVERY trial of EVERY variant converges on the same
614
+ // ~DEFAULT_HELP_PROBE_TIMEOUT_MS wait regardless of which is minimized, so the short-vs-long gap
615
+ // still collapses to ~0 and the caller's assertion still fails.
616
+ fn min_wedged_help_probe(wedge_script: &Path, probe_timeout_ms: &str, trials: u32) -> Duration {
617
+ (0..trials)
618
+ .map(|_| run_wedged_help_probe(wedge_script, probe_timeout_ms))
619
+ .min()
620
+ .expect("trials must be >= 1")
621
+ }
622
+
567
623
  #[cfg(not(feature = "cuda"))]
568
624
  #[test]
569
625
  fn test_help_probe_timeout_env_override_falls_back_fast_with_wedged_python() {
@@ -572,23 +628,48 @@ fn test_help_probe_timeout_env_override_falls_back_fast_with_wedged_python() {
572
628
  // override must make the native --help fallback trigger fast against a Python that never responds.
573
629
  //
574
630
  // #136: this asserted an ABSOLUTE `elapsed < 3s`, which false-failed under extreme GitHub-runner
575
- // starvation (spawn overhead alone exceeded the bound, blocking the v1.63.4 release). Instead RUN
576
- // IT TWICE -- a 250ms override vs a 3000ms override -- on the same host and COMPARE: the wedged
577
- // Python never responds, so each run waits its full probe timeout then falls back, and the short
578
- // run must finish ~2750ms sooner. Both runs pay identical spawn/fallback overhead, so the
579
- // DIFFERENCE is robust to CI contention (which inflates both equally); only the ~2750ms of
580
- // probe-wait the short run skips is measured -- never an absolute wall-clock.
631
+ // starvation (spawn overhead alone exceeded the bound, blocking the v1.63.4 release). Fix: run the
632
+ // wedged probe TWICE -- a 250ms override vs a longer one -- on the same host and assert the short
633
+ // run finishes markedly sooner, since shared contention cancels in the DIFFERENCE rather than an
634
+ // absolute wall-clock. That held for a while but STILL false-failed a 3rd time on the
635
+ // windows-latest/nightly leg and blocked v1.65.2 (#145) -- a single-shot pair remains vulnerable
636
+ // to a contention spike landing on just the short run (which shrinks the gap), or to racing the
637
+ // sibling test below, which drives the exact same `tg --help`-against-wedged-Python code path.
638
+ //
639
+ // #145 hardening -- three independent, complementary changes, not another tolerance bump alone:
640
+ // 1. `HELP_PROBE_TIMING_LOCK` mutually excludes this test and its sibling below so they never
641
+ // compete with EACH OTHER for process-creation resources (the single most directly
642
+ // identifiable shared-mechanism contention source).
643
+ // 2. Each variant is measured `HELP_PROBE_TRIALS` times and the MINIMUM is kept (see
644
+ // `min_wedged_help_probe`) so a single unlucky trial can no longer decide the result.
645
+ // 3. The long-side override is raised 3000ms -> 6000ms, doubling the nominal gap from ~2750ms
646
+ // to ~5750ms, while the required minimum gap rises only 1500ms -> 2500ms -- i.e. the
647
+ // required gap now needs to retain ~43% of the theoretical maximum instead of ~55%,
648
+ // materially MORE tolerant of contention eroding the observed gap, while staying far above
649
+ // the ~0ms gap a genuinely-ignored override would produce (both variants would then wait the
650
+ // same real ~3000ms default, regardless of trials or minimum-taking).
581
651
  let dir = tempdir().unwrap();
582
652
  let wedge_script = write_wedged_python_script(dir.path());
653
+ let _guard = lock_help_probe_timing();
583
654
 
584
- let elapsed_short = run_wedged_help_probe(&wedge_script, "250");
585
- let elapsed_long = run_wedged_help_probe(&wedge_script, "3000");
655
+ let elapsed_short = min_wedged_help_probe(
656
+ &wedge_script,
657
+ HELP_PROBE_SHORT_OVERRIDE_MS,
658
+ HELP_PROBE_TRIALS,
659
+ );
660
+ let elapsed_long = min_wedged_help_probe(
661
+ &wedge_script,
662
+ HELP_PROBE_LONG_OVERRIDE_MS,
663
+ HELP_PROBE_TRIALS,
664
+ );
586
665
 
587
666
  assert!(
588
- elapsed_short + Duration::from_millis(1500) < elapsed_long,
589
- "TG_HELP_PROBE_TIMEOUT_MS=250 was not honored -- the 250ms-override run took {elapsed_short:?} \
590
- but the 3000ms-override run took only {elapsed_long:?}; honoring 250ms should save ~2750ms of \
591
- probe-wait (require >=1500ms of that gap to survive timing jitter)"
667
+ elapsed_short + HELP_PROBE_MIN_GAP < elapsed_long,
668
+ "TG_HELP_PROBE_TIMEOUT_MS override was not honored -- the best of {HELP_PROBE_TRIALS} \
669
+ run(s) at {HELP_PROBE_SHORT_OVERRIDE_MS}ms took {elapsed_short:?}, but the best of \
670
+ {HELP_PROBE_TRIALS} run(s) at {HELP_PROBE_LONG_OVERRIDE_MS}ms took only {elapsed_long:?}; \
671
+ honoring the short override should save several seconds of probe-wait (required >= \
672
+ {HELP_PROBE_MIN_GAP:?} of that gap to survive timing jitter)"
592
673
  );
593
674
  }
594
675
 
@@ -605,8 +686,13 @@ fn test_help_probe_default_timeout_recovers_with_enriched_fallback_when_python_i
605
686
  // lower bound: a sibling attempt at that showed parallel-test subprocess-spawn contention can
606
687
  // inflate elapsed time by ~1.5-2x, which would make a tight bound flaky. That the override is
607
688
  // honored is covered precisely, without timing ambiguity, by the sibling test above.
689
+ //
690
+ // #145: shares `HELP_PROBE_TIMING_LOCK` with the override-honored test above so the two
691
+ // `tg --help`-against-wedged-Python timing tests never race each other for process-creation
692
+ // resources; see the lock's doc comment for why.
608
693
  let dir = tempdir().unwrap();
609
694
  let wedge_script = write_wedged_python_script(dir.path());
695
+ let _guard = lock_help_probe_timing();
610
696
 
611
697
  let mut tg = Command::new(env!("CARGO_BIN_EXE_tg"));
612
698
  tg.current_dir(repo_root())
@@ -674,6 +674,25 @@ class AstBackend(ComputeBackend):
674
674
  # silent false negative (sibling of the SILENT-FALLBACK class). Raise per base.py's
675
675
  # contract so run_command's except-BackendExecutionError handler reports a real
676
676
  # "invalid pattern" error instead of "0 matches".
677
+ #
678
+ # #144 hotfix / #141 DSL divergence: a bare identifier (e.g. "calculateTotal") that
679
+ # already failed the node-type-index lookup above and then fails to compile as a
680
+ # tree-sitter QUERY is not a malformed query -- it is an ast-grep-DSL code pattern
681
+ # (tg run --pattern's native surface), which only AstGrepWrapperBackend speaks. The
682
+ # native tree-sitter backend and the ast-grep wrapper are two different pattern DSLs;
683
+ # when the wrapper is unavailable (e.g. CI without the ast-grep binary) routing falls
684
+ # through to this native backend, which cannot serve that pattern. Fail closed with
685
+ # the documented ast-grep-dependency message (matches agent_readiness.py's
686
+ # skip_error_patterns) instead of the generic "invalid pattern" message, so an
687
+ # environment gap is not misclassified as a real query bug. A non-simple pattern
688
+ # (e.g. a malformed "(...)" query) keeps the original message unchanged.
689
+ if self._is_simple_node_type_pattern(pattern):
690
+ raise BackendExecutionError(
691
+ "Explicit AST search requires AST dependencies: the ast-grep wrapper "
692
+ f"backend is required for pattern {pattern!r} (the native tree-sitter "
693
+ "backend only serves structural node-type and (s-expression) queries, "
694
+ "not ast-grep code patterns)."
695
+ ) from exc
677
696
  raise BackendExecutionError(
678
697
  f"AST query compilation failed (invalid pattern for language {lang!r}?): {exc}"
679
698
  ) from exc
File without changes
File without changes