tensor-grep 1.45.2__tar.gz → 1.45.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 (129) hide show
  1. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/PKG-INFO +1 -1
  2. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/pyproject.toml +3 -1
  3. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/Cargo.lock +1 -1
  4. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/Cargo.toml +3 -1
  5. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/agent_capsule.py +83 -20
  6. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/repo_map.py +38 -22
  7. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/LICENSE +0 -0
  8. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/NOTICE +0 -0
  9. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/README.md +0 -0
  10. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/deny.toml +0 -0
  11. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/rust-toolchain.toml +0 -0
  12. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/backend_ast.rs +0 -0
  13. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/backend_ast_workflow.rs +0 -0
  14. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/backend_cpu.rs +0 -0
  15. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/backend_gpu.rs +0 -0
  16. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/bin/tg_search_fast.rs +0 -0
  17. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/cli.rs +0 -0
  18. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/crossover.rs +0 -0
  19. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/editor_plane.rs +0 -0
  20. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/gpu_native.rs +0 -0
  21. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/index.rs +0 -0
  22. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/lib.rs +0 -0
  23. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/main.rs +0 -0
  24. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/mmap_arrow.rs +0 -0
  25. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/native_search.rs +0 -0
  26. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/python_sidecar.rs +0 -0
  27. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/rg_passthrough.rs +0 -0
  28. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/routing.rs +0 -0
  29. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/src/runtime_paths.rs +0 -0
  30. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_ast_backend.rs +0 -0
  31. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_ast_cache.rs +0 -0
  32. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_ast_grep_embed.rs +0 -0
  33. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_ast_rewrite.rs +0 -0
  34. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_gpu_native.rs +0 -0
  35. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_gpu_native_error_handling.rs +0 -0
  36. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_gpu_native_graphs.rs +0 -0
  37. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_gpu_native_integration.rs +0 -0
  38. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_gpu_native_long_lines.rs +0 -0
  39. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_gpu_native_streams.rs +0 -0
  40. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_index.rs +0 -0
  41. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_mmap_arrow.rs +0 -0
  42. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_native_search.rs +0 -0
  43. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_output.rs +0 -0
  44. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_public_native_cli_parity.rs +0 -0
  45. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_python_bootstrap.rs +0 -0
  46. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_release_profile.rs +0 -0
  47. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_replace.rs +0 -0
  48. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_resident_worker.rs +0 -0
  49. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_routing.rs +0 -0
  50. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_runtime_path_resolution.rs +0 -0
  51. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_schema_compat.rs +0 -0
  52. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_search.rs +0 -0
  53. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_search_golden.rs +0 -0
  54. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_sidecar_ipc.rs +0 -0
  55. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/rust_core/tests/test_smart_routing.rs +0 -0
  56. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/__init__.py +0 -0
  57. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/__main__.py +0 -0
  58. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/__init__.py +0 -0
  59. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/ast_backend.py +0 -0
  60. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/ast_wrapper_backend.py +0 -0
  61. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/base.py +0 -0
  62. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/cpu_backend.py +0 -0
  63. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/cudf_backend.py +0 -0
  64. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/cybert_backend.py +0 -0
  65. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/ripgrep_backend.py +0 -0
  66. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/rust_backend.py +0 -0
  67. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/stringzilla_backend.py +0 -0
  68. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/backends/torch_backend.py +0 -0
  69. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/__init__.py +0 -0
  70. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/_index_lock.py +0 -0
  71. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/apply_policy.py +0 -0
  72. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/ast_workflows.py +0 -0
  73. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/audit_manifest.py +0 -0
  74. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/bootstrap.py +0 -0
  75. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/checkpoint_store.py +0 -0
  76. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/commands.py +0 -0
  77. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/docs_coverage.py +0 -0
  78. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/dogfood.py +0 -0
  79. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/formatters/__init__.py +0 -0
  80. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/formatters/base.py +0 -0
  81. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/formatters/csv_fmt.py +0 -0
  82. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/formatters/json_fmt.py +0 -0
  83. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/formatters/ripgrep_fmt.py +0 -0
  84. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/formatters/table_fmt.py +0 -0
  85. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/inventory.py +0 -0
  86. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/lang_go.py +0 -0
  87. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/lang_registry.py +0 -0
  88. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/lsp_external_provider.py +0 -0
  89. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/lsp_provider_setup.py +0 -0
  90. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/lsp_server.py +0 -0
  91. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/main.py +0 -0
  92. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/mcp_server.py +0 -0
  93. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/orient_capsule.py +0 -0
  94. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/progress.py +0 -0
  95. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/rg_contract.py +0 -0
  96. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/rule_packs.py +0 -0
  97. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/runtime_paths.py +0 -0
  98. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/scan_guardrails.py +0 -0
  99. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/session_daemon.py +0 -0
  100. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/session_store.py +0 -0
  101. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/cli/subprocess_policy.py +0 -0
  102. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/__init__.py +0 -0
  103. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/config.py +0 -0
  104. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/hardware/__init__.py +0 -0
  105. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/hardware/device_detect.py +0 -0
  106. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/hardware/device_inventory.py +0 -0
  107. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/hardware/memory_manager.py +0 -0
  108. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/observability.py +0 -0
  109. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/pipeline.py +0 -0
  110. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/query_analyzer.py +0 -0
  111. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/registration_check.py +0 -0
  112. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/reranker.py +0 -0
  113. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/result.py +0 -0
  114. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/retrieval_bm25.py +0 -0
  115. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/retrieval_chunker.py +0 -0
  116. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/retrieval_dense.py +0 -0
  117. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/retrieval_fusion.py +0 -0
  118. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/retrieval_lexical.py +0 -0
  119. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/retrieval_scoring.py +0 -0
  120. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/core/semantic_index.py +0 -0
  121. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/__init__.py +0 -0
  122. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/base.py +0 -0
  123. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/directory_scanner.py +0 -0
  124. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/reader_cudf.py +0 -0
  125. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/reader_dstorage.py +0 -0
  126. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/reader_fallback.py +0 -0
  127. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/io/reader_kvikio.py +0 -0
  128. {tensor_grep-1.45.2 → tensor_grep-1.45.4}/src/tensor_grep/perf_guard.py +0 -0
  129. {tensor_grep-1.45.2 → tensor_grep-1.45.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.45.2
3
+ Version: 1.45.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
@@ -399,12 +399,14 @@ version_variables = [
399
399
 
400
400
 
401
401
 
402
+
403
+
402
404
 
403
405
 
404
406
 
405
407
  [project]
406
408
  name = "tensor-grep"
407
- version = "1.45.2"
409
+ version = "1.45.4"
408
410
  description = "High-performance grep-compatible CLI with Rust, GPU, and AST/NLP routing"
409
411
  readme = { file = "rust_core/README.md", content-type = "text/markdown" }
410
412
  requires-python = ">=3.11"
@@ -1541,7 +1541,7 @@ dependencies = [
1541
1541
 
1542
1542
  [[package]]
1543
1543
  name = "tensor_grep_rs"
1544
- version = "1.45.2"
1544
+ version = "1.45.4"
1545
1545
  dependencies = [
1546
1546
  "aho-corasick",
1547
1547
  "anyhow",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "tensor_grep_rs"
3
- version = "1.45.2"
3
+ version = "1.45.4"
4
4
  edition = "2021"
5
5
  description = "Rust core engine for tensor-grep"
6
6
  license = "Apache-2.0"
@@ -306,6 +306,8 @@ path = "src/bin/tg_search_fast.rs"
306
306
 
307
307
 
308
308
 
309
+
310
+
309
311
 
310
312
 
311
313
 
@@ -20,11 +20,27 @@ _CAPSULE_LSP_CONFIDENCE_LANGUAGES = {"javascript", "php", "python", "rust", "typ
20
20
  # capsule snippets" fallback `_capsule_context_consistency` uses when the primary file never
21
21
  # appeared among the rendered sources at all (a genuine ranking miss, not a budget cut).
22
22
  _CAPSULE_TOKEN_BUDGET_OMISSION_REASON = "token budget exhausted"
23
- # Uplift ceiling for a *corroborated* token-budget-only primary omission. Deliberately below the
24
- # uncapped 0.9 default and matched to the >=0.75 "no ask-user" threshold (agent_capsule.py
23
+ # Historical uplift ceiling for a *corroborated* token-budget-only primary omission. Deliberately
24
+ # below the uncapped 0.9 default and matched to the >=0.75 "no ask-user" threshold (agent_capsule.py
25
25
  # `ask_user_before_editing` construction) -- this is a bounded relief from the 0.55 safety floor,
26
- # not a return to full confidence.
26
+ # not a return to full confidence. Kept for documentation of the original F4 floor; the active
27
+ # uplift ceiling used by `_apply_capsule_token_budget_confidence_uplift` is
28
+ # `_CAPSULE_GRAPH_CORROBORATED_CONFIDENCE_CAP` below.
27
29
  _CAPSULE_TOKEN_BUDGET_CONFIDENCE_UPLIFT_CAP = 0.75
30
+ # T2: a render-token-budget-only cut (`payload["truncated"]` cut some OTHER, lower-ranked source --
31
+ # the primary's OWN snippet still fits) is the SAME class of artifact as the capsule-own-budget
32
+ # primary omission above: a render/token-budget signal, not a resolution-quality signal. Once
33
+ # blast-radius call-site collection has graph-corroborated the primary, BOTH cases may rise to this
34
+ # higher ceiling rather than sitting at the historical 0.75 floor.
35
+ _CAPSULE_GRAPH_CORROBORATED_CONFIDENCE_CAP = 0.8
36
+ # The exact downgrade-reason strings that mean "confidence was reduced ONLY by a token/render
37
+ # budget artifact, not by a genuine resolution-ambiguity signal". Any OTHER downgrade reason
38
+ # (language mismatch, validation misalignment, alternative-target tie, marker-helper demotion)
39
+ # must disqualify the corroborated-resolution uplift below.
40
+ _CAPSULE_BUDGET_ONLY_DOWNGRADE_REASONS = frozenset({
41
+ "primary file omitted from capsule snippets by token budget",
42
+ "context omitted by token or render budget",
43
+ })
28
44
 
29
45
 
30
46
  def _as_dict(value: object) -> dict[str, Any]:
@@ -430,6 +446,7 @@ def _collect_capsule_call_site_evidence(
430
446
  include_blast_radius: bool,
431
447
  max_files: int,
432
448
  max_repo_files: int | None,
449
+ seed_confidence: float,
433
450
  ) -> tuple[list[dict[str, Any]], dict[str, Any]]:
434
451
  if not include_blast_radius:
435
452
  return [], {
@@ -447,7 +464,12 @@ def _collect_capsule_call_site_evidence(
447
464
  "status": "skipped",
448
465
  "reason": "primary symbol was not explicitly requested by query",
449
466
  }
450
- if _numeric_confidence(target.get("confidence"), 0.0) < 0.75:
467
+ # T2: gate on the caller-supplied PRE-cap seed confidence, not `target["confidence"]` -- by the
468
+ # time this runs, `target["confidence"]` may already have been mutated down by this module's
469
+ # OWN trust/tie/budget caps (`build_agent_capsule`). Gating on that post-cap value is circular:
470
+ # a target capped below 0.75 could never earn the very call-site evidence that would justify
471
+ # relief from that cap. See `_apply_capsule_token_budget_confidence_uplift`.
472
+ if seed_confidence < 0.75:
451
473
  return [], {
452
474
  "status": "skipped",
453
475
  "reason": "primary target confidence below call-site collection threshold",
@@ -1292,17 +1314,45 @@ def _capsule_token_budget_uplift_eligible(
1292
1314
  consistency: dict[str, Any],
1293
1315
  call_site_evidence: dict[str, Any],
1294
1316
  ) -> bool:
1317
+ """T2: eligibility for the corroborated-resolution uplift, covering BOTH the original
1318
+ capsule-own-budget primary omission (F4) and a render-truncated-only cut where the primary's
1319
+ OWN snippet is fully present (`payload["truncated"]` cut some other, lower-ranked source).
1320
+
1321
+ Every genuine-ambiguity signal must disqualify this uplift: a primary the ranking never
1322
+ selected/rendered at all, an unresolved alternative-target tie, an unrequested marker-helper
1323
+ demotion, or any downgrade reason outside the render/token-budget family (language mismatch,
1324
+ validation misalignment, ...). Only a target independently corroborated by the query AND by
1325
+ verified call-site evidence is eligible.
1326
+
1327
+ NOTE: `other_reasons` deliberately scans only `consistency["downgrade_reasons"]`, not
1328
+ `confidence["downgrade_reasons"]` -- the latter also carries a generic "context consistency
1329
+ downgraded confidence" restatement whenever `consistency["confidence_downgraded"]` is set for
1330
+ ANY reason (including the very budget-only omission this uplift targets), so scanning it would
1331
+ make the check disqualify itself. Every genuine (non-budget) cause of that flag already leaves
1332
+ its own specific, non-generic text in `consistency["downgrade_reasons"]` (trust mismatches) or
1333
+ is checked explicitly above (ties, marker-helper demotion, never-ranked primary).
1334
+ """
1295
1335
  if not snippets:
1296
1336
  return False
1297
- if not _capsule_primary_omission_is_token_budget_only(consistency):
1337
+ if consistency.get("primary_file_included") is False:
1338
+ return False
1339
+ if consistency.get("rendered_context_includes_primary") is False:
1340
+ return False
1341
+ if consistency.get("capsule_primary_file_omitted") and not (
1342
+ _capsule_primary_omission_is_token_budget_only(consistency)
1343
+ ):
1344
+ return False
1345
+ if consistency.get("alternative_confidence_tie"):
1298
1346
  return False
1299
- # Require the token-budget cut to be the ONLY confidence-downgrading signal in play -- if a
1300
- # trust-level conflict (language mismatch, validation misalignment), an alternative-target
1301
- # tie, or a marker-helper demotion is ALSO present, leave the existing (conservative)
1302
- # behavior untouched rather than trying to partially unwind a multi-cause downgrade.
1347
+ if _primary_target_is_unrequested_marker_helper(query, target):
1348
+ return False
1349
+ # Require the confidence hit to be ENTIRELY explained by the render/token-budget family -- if a
1350
+ # trust-level conflict (language mismatch, validation misalignment) or any other genuine
1351
+ # ambiguity signal is ALSO present, leave the existing (conservative) behavior untouched rather
1352
+ # than trying to partially unwind a multi-cause downgrade.
1303
1353
  other_reasons = {
1304
1354
  str(reason) for reason in (consistency.get("downgrade_reasons") or []) if reason
1305
- } - {"primary file omitted from capsule snippets by token budget"}
1355
+ } - _CAPSULE_BUDGET_ONLY_DOWNGRADE_REASONS
1306
1356
  if other_reasons:
1307
1357
  return False
1308
1358
  if not _primary_target_matches_query(query, target):
@@ -1322,17 +1372,24 @@ def _apply_capsule_token_budget_confidence_uplift(
1322
1372
  call_site_evidence: dict[str, Any],
1323
1373
  ask_reasons: list[str],
1324
1374
  ) -> None:
1325
- """Uplift the 0.55 primary-omission clamp to <=0.75 for a CORROBORATED token-budget-only
1326
- omission -- never for a genuine misroute (see `_capsule_primary_omission_is_token_budget_only`).
1375
+ """Uplift a render/token-budget-only confidence clamp for a CORROBORATED resolution -- never
1376
+ for a genuine misroute or a genuine ambiguity (see `_capsule_token_budget_uplift_eligible`).
1377
+
1378
+ T2 generalization: this originally only covered the 0.55 primary-omission clamp (the primary
1379
+ file cut from the capsule's OWN snippet budget). It now ALSO covers the 0.72 render-truncated
1380
+ tier (`payload["truncated"]` cut some OTHER, lower-ranked source, not the primary) -- both are
1381
+ render/token-budget artifacts, not resolution-quality signals, so both are eligible for the
1382
+ same corroborated-resolution relief up to `_CAPSULE_GRAPH_CORROBORATED_CONFIDENCE_CAP`.
1327
1383
 
1328
1384
  STRUCTURAL note: this must run AFTER `_collect_capsule_call_site_evidence` (agent_capsule.py
1329
1385
  call order), since verified caller evidence -- the corroboration this uplift depends on --
1330
1386
  isn't available until that call returns. It mutates `confidence`, `target`, `alternatives`,
1331
- and `ask_reasons` in place so `build_agent_capsule`'s already-assembled payload reflects the
1332
- uplift without re-deriving `ask_user_before_editing` from scratch.
1387
+ `consistency`, and `ask_reasons` in place so `build_agent_capsule`'s already-assembled payload
1388
+ reflects the uplift without re-deriving `ask_user_before_editing` from scratch.
1333
1389
  """
1334
1390
  current_overall = float(confidence.get("overall", 0.0))
1335
- if current_overall > 0.55:
1391
+ uplift_cap = _CAPSULE_GRAPH_CORROBORATED_CONFIDENCE_CAP
1392
+ if current_overall >= uplift_cap:
1336
1393
  return
1337
1394
  if not _capsule_token_budget_uplift_eligible(
1338
1395
  query=query,
@@ -1342,24 +1399,24 @@ def _apply_capsule_token_budget_confidence_uplift(
1342
1399
  call_site_evidence=call_site_evidence,
1343
1400
  ):
1344
1401
  return
1345
- uplifted = round(min(_CAPSULE_TOKEN_BUDGET_CONFIDENCE_UPLIFT_CAP, confidence_cap), 3)
1402
+ uplifted = round(min(uplift_cap, confidence_cap), 3)
1346
1403
  if uplifted <= current_overall:
1347
1404
  return
1348
1405
  confidence["overall"] = uplifted
1349
1406
  remaining_reasons = [
1350
1407
  reason
1351
1408
  for reason in confidence.get("downgrade_reasons", [])
1352
- if reason != "primary file omitted from capsule snippets by token budget"
1409
+ if reason not in _CAPSULE_BUDGET_ONLY_DOWNGRADE_REASONS
1353
1410
  ]
1354
1411
  remaining_reasons.append(
1355
- "primary file omitted by token budget only; uplifted to "
1356
- f"{uplifted} on corroborated call-site evidence"
1412
+ "token budget limited rendering only; confidence reflects graph-corroborated resolution"
1357
1413
  )
1358
1414
  confidence["downgrade_reasons"] = remaining_reasons
1359
1415
  consistency["capsule_token_budget_confidence_uplifted"] = True
1416
+ consistency["confidence_basis"] = "resolution-quality"
1360
1417
  _cap_primary_target_confidence(target, uplifted)
1361
1418
  _cap_alternative_target_confidences(alternatives, target)
1362
- # These three ask-reasons were added solely because of the primary-file-omission clamp we
1419
+ # These ask-reasons were added solely because of the render/token-budget confidence clamp we
1363
1420
  # just uplifted (asserted by the "no other downgrade reason" eligibility check above) -- clear
1364
1421
  # them so `ask_user_before_editing.required` deliberately flips to False for this case.
1365
1422
  ask_reasons[:] = [
@@ -1413,6 +1470,11 @@ def build_agent_capsule(
1413
1470
  all_alternatives = _alternative_targets(payload, target, limit=None)
1414
1471
  alternatives = all_alternatives[:4]
1415
1472
  target, alternatives = _prefer_implementation_over_marker_helper(query, target, alternatives)
1473
+ # T2: capture the RAW pre-cap seed confidence now, before any of this function's own trust/
1474
+ # tie/budget caps mutate `target["confidence"]` in place -- `_collect_capsule_call_site_evidence`
1475
+ # must gate on this seed value, not the post-cap one, or a capped target could never earn the
1476
+ # call-site evidence that would justify relief from that cap.
1477
+ primary_target_seed_confidence = _numeric_confidence(target.get("confidence"), 0.0)
1416
1478
  omitted_alternative_targets = max(0, len(all_alternatives) - len(alternatives))
1417
1479
  snippets, omitted_sources, _used_tokens = _build_snippets(
1418
1480
  payload,
@@ -1655,6 +1717,7 @@ def build_agent_capsule(
1655
1717
  include_blast_radius=include_blast_radius,
1656
1718
  max_files=max_files,
1657
1719
  max_repo_files=max_repo_files,
1720
+ seed_confidence=primary_target_seed_confidence,
1658
1721
  )
1659
1722
  # F4: verified call-site evidence is only available NOW (after the collection above), so the
1660
1723
  # token-budget-omission confidence uplift must happen here, post-hoc, rather than inside
@@ -13715,6 +13715,10 @@ def build_symbol_callers_from_map(
13715
13715
  normalized_provider = _normalize_semantic_provider(semantic_provider)
13716
13716
  external_calls: list[dict[str, Any]] = []
13717
13717
  fallback_used = False
13718
+ # Native call count captured BEFORE any lsp/hybrid merge -> the divergence signal for
13719
+ # provider_agreement (a partial LSP result must surface as diverged, not a clean lsp-only
13720
+ # proof). Mirrors build_symbol_refs_from_map's native_reference_count (H1 fix).
13721
+ native_call_count = len(calls)
13718
13722
  if normalized_provider != "native":
13719
13723
  external_refs = [
13720
13724
  dict(current)
@@ -13849,28 +13853,40 @@ def build_symbol_callers_from_map(
13849
13853
  **dict(alias_call),
13850
13854
  "provenance": f"lsp-{_language_for_path(Path(rust_file))}-fallback",
13851
13855
  })
13852
- if normalized_provider == "lsp":
13853
- calls = external_calls or calls
13854
- else:
13855
- merged_calls: dict[tuple[str, int, int], dict[str, Any]] = {}
13856
- for current_call_entry in [*external_calls, *calls]:
13857
- key = (
13858
- str(current_call_entry["file"]),
13859
- int(current_call_entry["line"]),
13860
- int(current_call_entry.get("end_line", current_call_entry["line"])),
13861
- )
13862
- if key in merged_calls:
13863
- merged_calls[key] = _merge_navigation_duplicate(
13864
- merged_calls[key],
13865
- dict(current_call_entry),
13866
- )
13867
- else:
13868
- merged_calls[key] = dict(current_call_entry)
13869
- calls = list(merged_calls.values())
13870
- calls.sort(
13871
- key=lambda item: (str(item["file"]), int(item["line"]), str(item.get("text", "")))
13856
+ # Merge (union) native + external calls for BOTH lsp and hybrid modes. A partial /
13857
+ # under-indexed LSP result must NEVER discard the correct native answer: the old
13858
+ # `calls = external_calls or calls` REPLACED the native call list with the (possibly
13859
+ # partial) LSP list in lsp mode, then native_count was recomputed from the REPLACED list
13860
+ # (=0) -> _merge_agreement_status always returned "lsp-only" + stamped lsp_proof: True,
13861
+ # silently dropping native-found call sites beyond a partial LSP index (H1: native finds
13862
+ # create_invoice() in a.py + b.py; a partial LSP index proves only a.py -> b.py is
13863
+ # silently dropped and the result stamped authoritative). Union keeps the native truth;
13864
+ # the provider_agreement + lsp_proof below are then stamped honestly (native>lsp ->
13865
+ # diverged). Mirrors build_symbol_refs_from_map's ref merge exactly.
13866
+ proof_calls = [current for current in external_calls if _is_lsp_proof_row(current)]
13867
+ merged_calls: dict[tuple[str, int, int], dict[str, Any]] = {}
13868
+ for current_call_entry in [*external_calls, *calls]:
13869
+ key = (
13870
+ str(current_call_entry["file"]),
13871
+ int(current_call_entry["line"]),
13872
+ int(current_call_entry.get("end_line", current_call_entry["line"])),
13872
13873
  )
13873
- calls = _dedupe_symbol_references(calls)
13874
+ if key in merged_calls:
13875
+ merged_calls[key] = _merge_navigation_duplicate(
13876
+ merged_calls[key],
13877
+ dict(current_call_entry),
13878
+ )
13879
+ else:
13880
+ merged_calls[key] = dict(current_call_entry)
13881
+ calls = list(merged_calls.values())
13882
+ calls.sort(
13883
+ key=lambda item: (str(item["file"]), int(item["line"]), str(item.get("text", "")))
13884
+ )
13885
+ calls = _dedupe_symbol_references(calls)
13886
+ if normalized_provider == "lsp" and len(proof_calls) < native_call_count:
13887
+ # LSP proved fewer calls than the native scan -> its index is incomplete for this
13888
+ # symbol; flag a fallback so the partial is not mis-reported as a clean lsp-only proof.
13889
+ fallback_used = True
13874
13890
 
13875
13891
  definition_locations = {
13876
13892
  (
@@ -13963,7 +13979,7 @@ def build_symbol_callers_from_map(
13963
13979
  fallback_used = True
13964
13980
  payload["provider_agreement"] = _merge_agreement_status(
13965
13981
  semantic_provider=normalized_provider,
13966
- native_count=len([current for current in calls if not _is_lsp_proof_row(current)]),
13982
+ native_count=native_call_count,
13967
13983
  lsp_count=lsp_proof_count,
13968
13984
  merged_count=len(calls),
13969
13985
  fallback_used=fallback_used,
File without changes
File without changes