conexus 3.2.2__tar.gz → 3.2.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.
Files changed (428) hide show
  1. {conexus-3.2.2 → conexus-3.2.4}/.claude-plugin/marketplace.json +2 -2
  2. {conexus-3.2.2 → conexus-3.2.4}/CHANGELOG.md +10 -0
  3. {conexus-3.2.2 → conexus-3.2.4}/CLAUDE.md +10 -9
  4. {conexus-3.2.2 → conexus-3.2.4}/PKG-INFO +1 -1
  5. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/README.md +1 -0
  6. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-006-chunk-size-configuration.md +1 -1
  7. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-048-streaming-pdf-pipeline.md +1 -1
  8. conexus-3.2.4/docs/rdr/rdr-054-chunk-boundary-equation-splitting.md +128 -0
  9. {conexus-3.2.2 → conexus-3.2.4}/nx/.claude-plugin/plugin.json +1 -1
  10. {conexus-3.2.2 → conexus-3.2.4}/nx/CHANGELOG.md +8 -0
  11. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/subagent-start.sh +3 -0
  12. {conexus-3.2.2 → conexus-3.2.4}/pyproject.toml +1 -1
  13. {conexus-3.2.2 → conexus-3.2.4}/sn/.claude-plugin/plugin.json +1 -1
  14. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/catalog.py +19 -6
  15. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/mcp_server.py +70 -14
  16. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/md_chunker.py +24 -11
  17. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pdf_chunker.py +1 -1
  18. {conexus-3.2.2 → conexus-3.2.4}/tests/test_md_chunker.py +95 -1
  19. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_chunker.py +11 -0
  20. {conexus-3.2.2 → conexus-3.2.4}/uv.lock +1 -1
  21. {conexus-3.2.2 → conexus-3.2.4}/.beads/.gitignore +0 -0
  22. {conexus-3.2.2 → conexus-3.2.4}/.beads/README.md +0 -0
  23. {conexus-3.2.2 → conexus-3.2.4}/.beads/config.yaml +0 -0
  24. {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/post-checkout +0 -0
  25. {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/post-merge +0 -0
  26. {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/pre-commit +0 -0
  27. {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/pre-push +0 -0
  28. {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/prepare-commit-msg +0 -0
  29. {conexus-3.2.2 → conexus-3.2.4}/.beads/interactions.jsonl +0 -0
  30. {conexus-3.2.2 → conexus-3.2.4}/.beads/issues.jsonl +0 -0
  31. {conexus-3.2.2 → conexus-3.2.4}/.beads/metadata.json +0 -0
  32. {conexus-3.2.2 → conexus-3.2.4}/.claude/skills/release.md +0 -0
  33. {conexus-3.2.2 → conexus-3.2.4}/.devcontainer/Dockerfile +0 -0
  34. {conexus-3.2.2 → conexus-3.2.4}/.devcontainer/devcontainer.json +0 -0
  35. {conexus-3.2.2 → conexus-3.2.4}/.dockerignore +0 -0
  36. {conexus-3.2.2 → conexus-3.2.4}/.env.example +0 -0
  37. {conexus-3.2.2 → conexus-3.2.4}/.gitattributes +0 -0
  38. {conexus-3.2.2 → conexus-3.2.4}/.github/workflows/ci.yml +0 -0
  39. {conexus-3.2.2 → conexus-3.2.4}/.github/workflows/release.yml +0 -0
  40. {conexus-3.2.2 → conexus-3.2.4}/.gitignore +0 -0
  41. {conexus-3.2.2 → conexus-3.2.4}/.markdownlint.json +0 -0
  42. {conexus-3.2.2 → conexus-3.2.4}/AGENTS.md +0 -0
  43. {conexus-3.2.2 → conexus-3.2.4}/Formula/nx.rb +0 -0
  44. {conexus-3.2.2 → conexus-3.2.4}/LICENSE +0 -0
  45. {conexus-3.2.2 → conexus-3.2.4}/README.md +0 -0
  46. {conexus-3.2.2 → conexus-3.2.4}/docs/README.md +0 -0
  47. {conexus-3.2.2 → conexus-3.2.4}/docs/architecture.md +0 -0
  48. {conexus-3.2.2 → conexus-3.2.4}/docs/catalog.md +0 -0
  49. {conexus-3.2.2 → conexus-3.2.4}/docs/cli-reference.md +0 -0
  50. {conexus-3.2.2 → conexus-3.2.4}/docs/configuration.md +0 -0
  51. {conexus-3.2.2 → conexus-3.2.4}/docs/contributing.md +0 -0
  52. {conexus-3.2.2 → conexus-3.2.4}/docs/getting-started.md +0 -0
  53. {conexus-3.2.2 → conexus-3.2.4}/docs/historical.md +0 -0
  54. {conexus-3.2.2 → conexus-3.2.4}/docs/memory-and-tasks.md +0 -0
  55. {conexus-3.2.2 → conexus-3.2.4}/docs/postmortem/2026-03-23-pdf-index-collection-mismatch.md +0 -0
  56. {conexus-3.2.2 → conexus-3.2.4}/docs/postmortem/2026-03-24-pdf-index-fix-not-applied.md +0 -0
  57. {conexus-3.2.2 → conexus-3.2.4}/docs/querying-guide.md +0 -0
  58. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/001-rdr-process-validation.md +0 -0
  59. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/002-t2-status-synchronization.md +0 -0
  60. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/010-t1-http-server.md +0 -0
  61. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/011-pdf-ingest-test-coverage.md +0 -0
  62. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/012-pdfplumber-extraction-tier.md +0 -0
  63. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/014-knowledge-base-retrieval-quality.md +0 -0
  64. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/015-indexing-pipeline-rethink.md +0 -0
  65. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/016-ast-chunk-line-range-bug.md +0 -0
  66. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/017-indexing-progress-reporting.md +0 -0
  67. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/018-replace-serve-with-git-hooks.md +0 -0
  68. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/023-agent-tool-permissions-audit.md +0 -0
  69. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/024-rdr-process-guardrails.md +0 -0
  70. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/028-language-registry-unification.md +0 -0
  71. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/029-pipeline-versioning.md +0 -0
  72. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/049-git-backed-catalog.md +0 -0
  73. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/050-catalog-query-integration.md +0 -0
  74. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/051-link-lifecycle.md +0 -0
  75. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/052-catalog-first-query-routing.md +0 -0
  76. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/053-xanadu-fidelity.md +0 -0
  77. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/cce-query-model-mismatch.md +0 -0
  78. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-001-rdr-process-validation.md +0 -0
  79. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-002-t2-status-synchronization.md +0 -0
  80. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-004-four-store-architecture.md +0 -0
  81. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-005-chromadb-cloud-quota-enforcement.md +0 -0
  82. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-007-claude-adoption-session-context-and-search-guidance.md +0 -0
  83. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-008-nx-workflow-integration.md +0 -0
  84. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-009-remove-agentic-and-answer-flags.md +0 -0
  85. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-010-t1-scratch-persistent-bounded-store.md +0 -0
  86. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-011-pdf-ingest-test-coverage.md +0 -0
  87. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-012-pdfplumber-extraction-tier.md +0 -0
  88. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-013-remove-nx-pm-layer.md +0 -0
  89. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-014-knowledge-base-retrieval-quality.md +0 -0
  90. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-015-indexing-pipeline-rethink.md +0 -0
  91. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-016-ast-chunk-line-range-bug.md +0 -0
  92. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-017-indexing-progress-reporting.md +0 -0
  93. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-018-replace-serve-with-git-hooks.md +0 -0
  94. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-019-chromadb-transient-retry.md +0 -0
  95. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-020-voyage-chromadb-read-timeout.md +0 -0
  96. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-021-docling-pdf-extraction.md +0 -0
  97. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-022-memory-delete-command.md +0 -0
  98. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-023-agent-tool-permissions-audit.md +0 -0
  99. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-024-rdr-process-guardrails.md +0 -0
  100. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-025-language-agnostic-agents.md +0 -0
  101. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-026-hybrid-search-fusion.md +0 -0
  102. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-027-search-results-ux.md +0 -0
  103. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-028-code-search-recall.md +0 -0
  104. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-029-pipeline-versioning.md +0 -0
  105. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-030-reliability-hardening.md +0 -0
  106. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-031-collection-portability.md +0 -0
  107. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-032-indexer-decomposition.md +0 -0
  108. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-033-pdf-agent-nx-index-alignment.md +0 -0
  109. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-034-mcp-server-agent-storage.md +0 -0
  110. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-035-plugin-agent-mcp-tool-access.md +0 -0
  111. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-036-post-accept-planning-workflow.md +0 -0
  112. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-037-t3-database-consolidation.md +0 -0
  113. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-038-local-t3-backend.md +0 -0
  114. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-039-claude-code-framework-alignment.md +0 -0
  115. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-040-cce-postmortem-gaps-mcp-enhancement.md +0 -0
  116. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-040-developer-agent-circuit-breaker.md +0 -0
  117. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-041-t1-scratch-inter-agent-context.md +0 -0
  118. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-042-agenticscholar-enhancements.md +0 -0
  119. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-043-plan-enricher-scope.md +0 -0
  120. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-044-math-aware-pdf-extraction.md +0 -0
  121. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-045-post-implementation-verification.md +0 -0
  122. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-046-mineru-server-backed-extraction.md +0 -0
  123. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-047-large-pdf-extraction-resilience.md +0 -0
  124. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-049-consolidation-plan.md +0 -0
  125. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-049-git-backed-catalog.md +0 -0
  126. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-050-knowledge-graph-query-planning.md +0 -0
  127. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-051-link-lifecycle.md +0 -0
  128. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-052-catalog-first-query-routing.md +0 -0
  129. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-053-xanadu-fidelity.md +0 -0
  130. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-nexus-integration.md +0 -0
  131. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-overview.md +0 -0
  132. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-templates.md +0 -0
  133. {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-workflow.md +0 -0
  134. {conexus-3.2.2 → conexus-3.2.4}/docs/repo-indexing.md +0 -0
  135. {conexus-3.2.2 → conexus-3.2.4}/docs/storage-tiers.md +0 -0
  136. {conexus-3.2.2 → conexus-3.2.4}/docs/xanadu-in-nexus.md +0 -0
  137. {conexus-3.2.2 → conexus-3.2.4}/nx/.mcp.json +0 -0
  138. {conexus-3.2.2 → conexus-3.2.4}/nx/README.md +0 -0
  139. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/CONTEXT_PROTOCOL.md +0 -0
  140. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/ERROR_HANDLING.md +0 -0
  141. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/MAINTENANCE.md +0 -0
  142. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/README.md +0 -0
  143. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/RELAY_TEMPLATE.md +0 -0
  144. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/analytical-operator.md +0 -0
  145. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/architect-planner.md +0 -0
  146. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/code-review-expert.md +0 -0
  147. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/codebase-deep-analyzer.md +0 -0
  148. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/debugger.md +0 -0
  149. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/deep-analyst.md +0 -0
  150. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/deep-research-synthesizer.md +0 -0
  151. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/developer.md +0 -0
  152. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/knowledge-tidier.md +0 -0
  153. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/orchestrator.md +0 -0
  154. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/pdf-chromadb-processor.md +0 -0
  155. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/plan-auditor.md +0 -0
  156. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/plan-enricher.md +0 -0
  157. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/query-planner.md +0 -0
  158. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/strategic-planner.md +0 -0
  159. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/substantive-critic.md +0 -0
  160. {conexus-3.2.2 → conexus-3.2.4}/nx/agents/test-validator.md +0 -0
  161. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/analyze-code.md +0 -0
  162. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/architecture.md +0 -0
  163. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/create-plan.md +0 -0
  164. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/debug.md +0 -0
  165. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/deep-analysis.md +0 -0
  166. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/enrich-plan.md +0 -0
  167. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/implement.md +0 -0
  168. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/knowledge-tidy.md +0 -0
  169. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/nx-preflight.md +0 -0
  170. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/pdf-process.md +0 -0
  171. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/plan-audit.md +0 -0
  172. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-accept.md +0 -0
  173. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-close.md +0 -0
  174. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-create.md +0 -0
  175. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-gate.md +0 -0
  176. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-list.md +0 -0
  177. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-research.md +0 -0
  178. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-show.md +0 -0
  179. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/research.md +0 -0
  180. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/review-code.md +0 -0
  181. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/substantive-critique.md +0 -0
  182. {conexus-3.2.2 → conexus-3.2.4}/nx/commands/test-validate.md +0 -0
  183. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/hooks.json +0 -0
  184. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/auto-approve-nx-mcp.sh +0 -0
  185. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/post_compact_hook.sh +0 -0
  186. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/pre_close_verification_hook.sh +0 -0
  187. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/rdr_hook.py +0 -0
  188. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/read_verification_config.py +0 -0
  189. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/session_start_hook.py +0 -0
  190. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/stop_failure_hook.py +0 -0
  191. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/stop_verification_hook.sh +0 -0
  192. {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/t2_prefix_scan.py +0 -0
  193. {conexus-3.2.2 → conexus-3.2.4}/nx/registry.yaml +0 -0
  194. {conexus-3.2.2 → conexus-3.2.4}/nx/resources/rdr/README-TEMPLATE.md +0 -0
  195. {conexus-3.2.2 → conexus-3.2.4}/nx/resources/rdr/TEMPLATE.md +0 -0
  196. {conexus-3.2.2 → conexus-3.2.4}/nx/resources/rdr/post-mortem/TEMPLATE.md +0 -0
  197. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/architecture/SKILL.md +0 -0
  198. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/brainstorming-gate/SKILL.md +0 -0
  199. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/cli-controller/SKILL.md +0 -0
  200. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/code-review/SKILL.md +0 -0
  201. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/codebase-analysis/SKILL.md +0 -0
  202. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/debugging/SKILL.md +0 -0
  203. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/deep-analysis/SKILL.md +0 -0
  204. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/development/SKILL.md +0 -0
  205. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/enrich-plan/SKILL.md +0 -0
  206. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/finishing-branch/SKILL.md +0 -0
  207. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/git-worktrees/SKILL.md +0 -0
  208. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/knowledge-tidying/SKILL.md +0 -0
  209. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/nexus/SKILL.md +0 -0
  210. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/nexus/reference.md +0 -0
  211. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/orchestration/SKILL.md +0 -0
  212. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/pdf-processing/SKILL.md +0 -0
  213. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/plan-validation/SKILL.md +0 -0
  214. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/query/SKILL.md +0 -0
  215. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-accept/SKILL.md +0 -0
  216. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-close/SKILL.md +0 -0
  217. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-create/SKILL.md +0 -0
  218. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-gate/SKILL.md +0 -0
  219. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-list/SKILL.md +0 -0
  220. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-research/SKILL.md +0 -0
  221. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-show/SKILL.md +0 -0
  222. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/receiving-review/SKILL.md +0 -0
  223. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/research-synthesis/SKILL.md +0 -0
  224. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/serena-code-nav/SKILL.md +0 -0
  225. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/strategic-planning/SKILL.md +0 -0
  226. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/substantive-critique/SKILL.md +0 -0
  227. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/test-validation/SKILL.md +0 -0
  228. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/using-nx-skills/SKILL.md +0 -0
  229. {conexus-3.2.2 → conexus-3.2.4}/nx/skills/writing-nx-skills/SKILL.md +0 -0
  230. {conexus-3.2.2 → conexus-3.2.4}/scripts/reinstall-tool.sh +0 -0
  231. {conexus-3.2.2 → conexus-3.2.4}/sn/.mcp.json +0 -0
  232. {conexus-3.2.2 → conexus-3.2.4}/sn/README.md +0 -0
  233. {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/hooks.json +0 -0
  234. {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/scripts/auto-approve-sn-mcp.sh +0 -0
  235. {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/scripts/mcp-inject.sh +0 -0
  236. {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/scripts/session-start.sh +0 -0
  237. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/__init__.py +0 -0
  238. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/bib_enricher.py +0 -0
  239. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/__init__.py +0 -0
  240. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/auto_linker.py +0 -0
  241. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/catalog.py +0 -0
  242. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/catalog_db.py +0 -0
  243. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/consolidation.py +0 -0
  244. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/link_generator.py +0 -0
  245. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/tumbler.py +0 -0
  246. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/checkpoint.py +0 -0
  247. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/chunker.py +0 -0
  248. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/classifier.py +0 -0
  249. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/cli.py +0 -0
  250. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/code_indexer.py +0 -0
  251. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/__init__.py +0 -0
  252. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/_helpers.py +0 -0
  253. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/_provision.py +0 -0
  254. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/collection.py +0 -0
  255. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/config_cmd.py +0 -0
  256. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/doctor.py +0 -0
  257. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/enrich.py +0 -0
  258. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/hook.py +0 -0
  259. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/hooks.py +0 -0
  260. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/index.py +0 -0
  261. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/memory.py +0 -0
  262. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/mineru.py +0 -0
  263. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/scratch.py +0 -0
  264. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/search_cmd.py +0 -0
  265. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/store.py +0 -0
  266. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/config.py +0 -0
  267. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/corpus.py +0 -0
  268. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/__init__.py +0 -0
  269. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/chroma_quotas.py +0 -0
  270. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/local_ef.py +0 -0
  271. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/t1.py +0 -0
  272. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/t2.py +0 -0
  273. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/t3.py +0 -0
  274. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/doc_indexer.py +0 -0
  275. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/errors.py +0 -0
  276. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/exporter.py +0 -0
  277. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/formatters.py +0 -0
  278. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/frecency.py +0 -0
  279. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/hooks.py +0 -0
  280. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/index_context.py +0 -0
  281. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/indexer.py +0 -0
  282. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/indexer_utils.py +0 -0
  283. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/languages.py +0 -0
  284. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pdf_extractor.py +0 -0
  285. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pipeline_buffer.py +0 -0
  286. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pipeline_stages.py +0 -0
  287. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/prose_indexer.py +0 -0
  288. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/registry.py +0 -0
  289. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/retry.py +0 -0
  290. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/ripgrep_cache.py +0 -0
  291. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/scoring.py +0 -0
  292. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/search_engine.py +0 -0
  293. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/session.py +0 -0
  294. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/ttl.py +0 -0
  295. {conexus-3.2.2 → conexus-3.2.4}/src/nexus/types.py +0 -0
  296. {conexus-3.2.2 → conexus-3.2.4}/tests/__init__.py +0 -0
  297. {conexus-3.2.2 → conexus-3.2.4}/tests/__snapshots__/test_search_snapshot.ambr +0 -0
  298. {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/__init__.py +0 -0
  299. {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/corpus.json +0 -0
  300. {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/queries.json +0 -0
  301. {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/test_retrieval_ndcg.py +0 -0
  302. {conexus-3.2.2 → conexus-3.2.4}/tests/conftest.py +0 -0
  303. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/auth-login.sh +0 -0
  304. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/lib.sh +0 -0
  305. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/run.sh +0 -0
  306. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/sandbox.sh +0 -0
  307. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/00_debug_load.sh +0 -0
  308. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/01_smoke.sh +0 -0
  309. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/02_sequential_thinking.sh +0 -0
  310. {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/03_skills.sh +0 -0
  311. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/__init__.py +0 -0
  312. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_permission_request_hooks.py +0 -0
  313. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_post_compact_hook.py +0 -0
  314. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_pre_close_verification_hook.py +0 -0
  315. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_read_verification_config.py +0 -0
  316. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_stop_failure_hook.py +0 -0
  317. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_stop_verification_hook.py +0 -0
  318. {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_verification_integration.py +0 -0
  319. {conexus-3.2.2 → conexus-3.2.4}/tests/test_ast_languages.py +0 -0
  320. {conexus-3.2.2 → conexus-3.2.4}/tests/test_auto_linker.py +0 -0
  321. {conexus-3.2.2 → conexus-3.2.4}/tests/test_backfill_hash.py +0 -0
  322. {conexus-3.2.2 → conexus-3.2.4}/tests/test_bib_enricher.py +0 -0
  323. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog.py +0 -0
  324. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_backfill.py +0 -0
  325. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_cli.py +0 -0
  326. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_consolidation.py +0 -0
  327. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_db.py +0 -0
  328. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_e2e.py +0 -0
  329. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_git.py +0 -0
  330. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_indexer_hook.py +0 -0
  331. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_jsonl.py +0 -0
  332. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_knowledge_hook.py +0 -0
  333. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_link_generation.py +0 -0
  334. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_links.py +0 -0
  335. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_mcp.py +0 -0
  336. {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_pdf_hook.py +0 -0
  337. {conexus-3.2.2 → conexus-3.2.4}/tests/test_checkpoint.py +0 -0
  338. {conexus-3.2.2 → conexus-3.2.4}/tests/test_chroma_quotas.py +0 -0
  339. {conexus-3.2.2 → conexus-3.2.4}/tests/test_chroma_retry.py +0 -0
  340. {conexus-3.2.2 → conexus-3.2.4}/tests/test_chunker.py +0 -0
  341. {conexus-3.2.2 → conexus-3.2.4}/tests/test_chunker_ast_languages.py +0 -0
  342. {conexus-3.2.2 → conexus-3.2.4}/tests/test_classifier.py +0 -0
  343. {conexus-3.2.2 → conexus-3.2.4}/tests/test_collection_cmd.py +0 -0
  344. {conexus-3.2.2 → conexus-3.2.4}/tests/test_config.py +0 -0
  345. {conexus-3.2.2 → conexus-3.2.4}/tests/test_config_cmd.py +0 -0
  346. {conexus-3.2.2 → conexus-3.2.4}/tests/test_corpus.py +0 -0
  347. {conexus-3.2.2 → conexus-3.2.4}/tests/test_doc_indexer.py +0 -0
  348. {conexus-3.2.2 → conexus-3.2.4}/tests/test_doc_indexer_hash_sync.py +0 -0
  349. {conexus-3.2.2 → conexus-3.2.4}/tests/test_doc_indexer_pagination.py +0 -0
  350. {conexus-3.2.2 → conexus-3.2.4}/tests/test_doctor_cmd.py +0 -0
  351. {conexus-3.2.2 → conexus-3.2.4}/tests/test_doctor_integrity.py +0 -0
  352. {conexus-3.2.2 → conexus-3.2.4}/tests/test_e2e.py +0 -0
  353. {conexus-3.2.2 → conexus-3.2.4}/tests/test_enrich_command.py +0 -0
  354. {conexus-3.2.2 → conexus-3.2.4}/tests/test_exporter.py +0 -0
  355. {conexus-3.2.2 → conexus-3.2.4}/tests/test_formatters.py +0 -0
  356. {conexus-3.2.2 → conexus-3.2.4}/tests/test_frecency.py +0 -0
  357. {conexus-3.2.2 → conexus-3.2.4}/tests/test_git_hooks.py +0 -0
  358. {conexus-3.2.2 → conexus-3.2.4}/tests/test_hooks.py +0 -0
  359. {conexus-3.2.2 → conexus-3.2.4}/tests/test_hybrid_boost.py +0 -0
  360. {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_cmd.py +0 -0
  361. {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_lock.py +0 -0
  362. {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_pdf_batch.py +0 -0
  363. {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_rdr_cmd.py +0 -0
  364. {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_reminder.py +0 -0
  365. {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer.py +0 -0
  366. {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer_chunk_flow.py +0 -0
  367. {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer_e2e.py +0 -0
  368. {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer_modules.py +0 -0
  369. {conexus-3.2.2 → conexus-3.2.4}/tests/test_integration.py +0 -0
  370. {conexus-3.2.2 → conexus-3.2.4}/tests/test_jsonl.py +0 -0
  371. {conexus-3.2.2 → conexus-3.2.4}/tests/test_languages.py +0 -0
  372. {conexus-3.2.2 → conexus-3.2.4}/tests/test_local_mode.py +0 -0
  373. {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_concurrency.py +0 -0
  374. {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_integration.py +0 -0
  375. {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_server.py +0 -0
  376. {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_session.py +0 -0
  377. {conexus-3.2.2 → conexus-3.2.4}/tests/test_md_chunker_semantic_integrity.py +0 -0
  378. {conexus-3.2.2 → conexus-3.2.4}/tests/test_md_preservation.py +0 -0
  379. {conexus-3.2.2 → conexus-3.2.4}/tests/test_memory.py +0 -0
  380. {conexus-3.2.2 → conexus-3.2.4}/tests/test_mineru_cmd.py +0 -0
  381. {conexus-3.2.2 → conexus-3.2.4}/tests/test_mineru_extractor.py +0 -0
  382. {conexus-3.2.2 → conexus-3.2.4}/tests/test_minified_chunking.py +0 -0
  383. {conexus-3.2.2 → conexus-3.2.4}/tests/test_p0_regressions.py +0 -0
  384. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_chunker_integration.py +0 -0
  385. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_e2e.py +0 -0
  386. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor.py +0 -0
  387. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor_integration.py +0 -0
  388. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor_normalization.py +0 -0
  389. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor_server.py +0 -0
  390. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_normalization.py +0 -0
  391. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_subsystem.py +0 -0
  392. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pipeline_buffer.py +0 -0
  393. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pipeline_stages.py +0 -0
  394. {conexus-3.2.2 → conexus-3.2.4}/tests/test_pipeline_version.py +0 -0
  395. {conexus-3.2.2 → conexus-3.2.4}/tests/test_plan_library.py +0 -0
  396. {conexus-3.2.2 → conexus-3.2.4}/tests/test_plugin.py +0 -0
  397. {conexus-3.2.2 → conexus-3.2.4}/tests/test_plugin_install.py +0 -0
  398. {conexus-3.2.2 → conexus-3.2.4}/tests/test_plugin_structure.py +0 -0
  399. {conexus-3.2.2 → conexus-3.2.4}/tests/test_ppid_chain_hypothesis.py +0 -0
  400. {conexus-3.2.2 → conexus-3.2.4}/tests/test_provision.py +0 -0
  401. {conexus-3.2.2 → conexus-3.2.4}/tests/test_rdr052_verification.py +0 -0
  402. {conexus-3.2.2 → conexus-3.2.4}/tests/test_rdr053_verification.py +0 -0
  403. {conexus-3.2.2 → conexus-3.2.4}/tests/test_registry.py +0 -0
  404. {conexus-3.2.2 → conexus-3.2.4}/tests/test_ripgrep_cache.py +0 -0
  405. {conexus-3.2.2 → conexus-3.2.4}/tests/test_schema.py +0 -0
  406. {conexus-3.2.2 → conexus-3.2.4}/tests/test_scoring.py +0 -0
  407. {conexus-3.2.2 → conexus-3.2.4}/tests/test_scratch.py +0 -0
  408. {conexus-3.2.2 → conexus-3.2.4}/tests/test_scratch_cmd.py +0 -0
  409. {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_cmd.py +0 -0
  410. {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_engine.py +0 -0
  411. {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_modules.py +0 -0
  412. {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_snapshot.py +0 -0
  413. {conexus-3.2.2 → conexus-3.2.4}/tests/test_session.py +0 -0
  414. {conexus-3.2.2 → conexus-3.2.4}/tests/test_session_propagation_hypotheses.py +0 -0
  415. {conexus-3.2.2 → conexus-3.2.4}/tests/test_silent_error_logging.py +0 -0
  416. {conexus-3.2.2 → conexus-3.2.4}/tests/test_sn_plugin.py +0 -0
  417. {conexus-3.2.2 → conexus-3.2.4}/tests/test_store_cmd.py +0 -0
  418. {conexus-3.2.2 → conexus-3.2.4}/tests/test_t1.py +0 -0
  419. {conexus-3.2.2 → conexus-3.2.4}/tests/test_t2.py +0 -0
  420. {conexus-3.2.2 → conexus-3.2.4}/tests/test_t2_prefix_scan.py +0 -0
  421. {conexus-3.2.2 → conexus-3.2.4}/tests/test_t3.py +0 -0
  422. {conexus-3.2.2 → conexus-3.2.4}/tests/test_t3_quota_enforcement.py +0 -0
  423. {conexus-3.2.2 → conexus-3.2.4}/tests/test_table_extraction.py +0 -0
  424. {conexus-3.2.2 → conexus-3.2.4}/tests/test_ttl.py +0 -0
  425. {conexus-3.2.2 → conexus-3.2.4}/tests/test_tumbler.py +0 -0
  426. {conexus-3.2.2 → conexus-3.2.4}/tests/test_tuning_config.py +0 -0
  427. {conexus-3.2.2 → conexus-3.2.4}/tests/test_types_and_errors.py +0 -0
  428. {conexus-3.2.2 → conexus-3.2.4}/tests/test_voyage_retry.py +0 -0
@@ -9,13 +9,13 @@
9
9
  "name": "nx",
10
10
  "source": "./nx",
11
11
  "description": "Self-hosted three-tier knowledge management with 17 specialized agents, analytical query pipelines, semantic search, and RDR decision tracking for Claude Code.",
12
- "version": "3.2.2"
12
+ "version": "3.2.4"
13
13
  },
14
14
  {
15
15
  "name": "sn",
16
16
  "source": "./sn",
17
17
  "description": "Injects Serena and Context7 MCP tool usage guidance into subagents via SubagentStart hook.",
18
- "version": "3.2.2"
18
+ "version": "3.2.4"
19
19
  }
20
20
  ]
21
21
  }
@@ -6,6 +6,16 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.2.4] - 2026-04-07
10
+
11
+ ### Fixed
12
+ - **Chunk boundary overlap** (RDR-054) — wired dead `overlap_chars` into `SemanticMarkdownChunker._split_large_section`, which previously had zero overlap between sub-chunks. Bumped `PDFChunker` default overlap from 15% to 20% (225 → 300 chars). Fixed header duplication bug when overlap exceeds emitted content length. Guarded Python `[-0:]` edge case.
13
+
14
+ ## [3.2.3] - 2026-04-07
15
+
16
+ ### Fixed
17
+ - **Pagination completeness** — all list-returning MCP tools and CLI commands now include pagination footers when results are truncated. Tools fixed: `query`, `scratch` (search/list), `plan_search`, `catalog_search`, `catalog_list`, `catalog_link_query`. CLI commands fixed: `nx catalog list`, `nx catalog search`, `nx catalog links`. Docstrings updated to document pagination behavior.
18
+
9
19
  ## [3.2.2] - 2026-04-07
10
20
 
11
21
  ### Fixed
@@ -62,15 +62,15 @@ Nexus is a Python 3.12+ CLI + persistent server for semantic search and knowledg
62
62
 
63
63
  **Catalog (T3 metadata layer)**: Git-backed document registry that tracks *what* is indexed and *how documents relate*. JSONL files are the source of truth; SQLite + FTS5 is the query cache (rebuilt automatically on mtime change). Tumblers (hierarchical addresses like `1.2.5`) identify documents. Every indexing pathway (`index repo`, `index pdf`, `index rdr`, MCP `store_put`) auto-registers entries. `nx catalog setup` creates and populates the catalog in one step.
64
64
 
65
- **Link graph**: Typed edges between documents agents create these during their work:
66
- - `cites` — citation (auto from `nx enrich` via Semantic Scholar, or by research agents)
67
- - `implements-heuristic` — code→RDR (auto from indexer, title substring match)
68
- - `supersedes` — replacement (by rdr-close, knowledge-tidier)
69
- - `relates` — related findings (by debugger, deep-analyst, codebase-analyzer, architect-planner)
70
- - `implements` — manual or by developer agent linking insights to RDRs
71
- - `created_by` tracks provenance: which agent or user created each link
65
+ **Link graph**: Typed edges between documents (`cites`, `implements`, `implements-heuristic`, `supersedes`, `relates`, or custom). `created_by` tracks provenance. Three creation paths:
72
66
 
73
- **Two graph views**: `catalog_links` MCP tool returns live-document links only. `catalog_link_query` returns all links including orphans (for audit). The `query` MCP tool has catalog-aware routing (`author`, `content_type`, `subtree`, `follow_links`, `depth` params) for scoped search in a single call. The `/nx:query` skill orchestrates multi-step analytical queries via three-path dispatch (single query → template match → planner).
67
+ 1. **Post-hoc** (batch, after indexing): `generate_citation_links()`, `generate_code_rdr_links()`, `generate_rdr_filepath_links()` in `link_generator.py`
68
+ 2. **Auto-linker** (`auto_linker.py`): fires on every `store_put` MCP call, reads `link-context` from T1 scratch (tag: `link-context`), creates links to seeded targets. Skills seed before dispatch; agents self-seed from their task prompt when no context exists.
69
+ 3. **Agent-direct**: agents call `catalog_link` MCP tool during work for precise typed links
70
+
71
+ **Two graph views**: `catalog_links` returns live-document links only. `catalog_link_query` returns all including orphans. The `query` MCP tool has catalog-aware routing (`author`, `content_type`, `subtree`, `follow_links`, `depth`) for scoped search.
72
+
73
+ **Pagination**: All list-returning tools include footers when truncated — `offset=N` for next page.
74
74
 
75
75
  **T3 expire guard**: always filter `ttl_days > 0 AND expires_at != "" AND expires_at < now` — the `expires_at != ""` guard is mandatory: permanent entries use `expires_at=""` which sorts before ISO timestamps and would be incorrectly deleted by a 2-condition guard.
76
76
 
@@ -84,7 +84,8 @@ src/nexus/ # Core package
84
84
  catalog.py # Core: link(), link_query(), graph(), delete_document(), link_audit(), descendants(), resolve_chunk()
85
85
  catalog_db.py # SQLite schema + FTS5 + UNIQUE link constraint + descendants() SQL helper
86
86
  tumbler.py # Hierarchical addresses (depth, ancestors, lca) + JSONL readers with resilience
87
- link_generator.py # Auto-generate citation + code-RDR links from metadata
87
+ auto_linker.py # Storage-boundary auto-linking from T1 scratch link-context
88
+ link_generator.py # Post-hoc batch linkers: citation, code-RDR heuristic, RDR file-path
88
89
  db/ # t1.py, t2.py, t3.py — tier implementations; local_ef.py — local ONNX embeddings
89
90
  indexer.py # Repo indexing pipeline (classify → chunk → embed → store)
90
91
  classifier.py # File classification: CODE / PROSE / PDF / SKIP
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conexus
3
- Version: 3.2.2
3
+ Version: 3.2.4
4
4
  Summary: Self-hosted semantic search and knowledge management for LLM-driven development
5
5
  Project-URL: Homepage, https://github.com/Hellblazer/nexus
6
6
  Project-URL: Repository, https://github.com/Hellblazer/nexus
@@ -75,6 +75,7 @@ An RDR (Research-Design-Review) is a short document that records a technical dec
75
75
  | [RDR-051](rdr-051-link-lifecycle.md) | Link Lifecycle: Full CRUD, Queryable Links, Bulk Operations | Architecture | Closed | 2026-04-05 |
76
76
  | [RDR-052](rdr-052-catalog-first-query-routing.md) | Catalog-First Query Routing — Push Planning into MCP | Architecture | Closed | 2026-04-05 |
77
77
  | [RDR-053](rdr-053-xanadu-fidelity.md) | Xanadu Fidelity — Tumbler Arithmetic and Content-Addressed Spans | Architecture | Closed | 2026-04-05 |
78
+ | [RDR-054](rdr-054-chunk-boundary-equation-splitting.md) | Chunk Boundary Equation Splitting — Information Loss at Chunk Boundaries | Bug | Closed | 2026-04-07 |
78
79
 
79
80
  ---
80
81
 
@@ -239,7 +239,7 @@ nx index repo PATH
239
239
  ```
240
240
 
241
241
  Markdown prose uses `SemanticMarkdownChunker(chunk_size=512, chunk_overlap=50)` (tokens).
242
- PDFs use `PDFChunker(chunk_chars=1500, overlap_percent=0.15)`.
242
+ PDFs use `PDFChunker(chunk_chars=1500, overlap_percent=0.20)`.
243
243
  Both are out of scope — this RDR addresses code files only.
244
244
 
245
245
  ### R3: Scope of change (Confirmed)
@@ -311,7 +311,7 @@ Three concurrent threads need coordinated shutdown when any stage fails. Standar
311
311
  **Current pipeline memory for 771-page CMRB book**:
312
312
  - Extraction: `md_parts` list — 771 page strings, ~2-5 MB total
313
313
  - `"\n".join(md_parts)` — creates a second copy, ~2-5 MB
314
- - `PDFChunker.chunk()` — returns ~2000 `TextChunk` objects, each holding a copy of its text. Total: ~3-5 MB (overlapping chunks mean ~15% extra text)
314
+ - `PDFChunker.chunk()` — returns ~2000 `TextChunk` objects, each holding a copy of its text. Total: ~3-5 MB (overlapping chunks mean ~20% extra text)
315
315
  - `_embed_with_fallback` — embedding vectors: 2000 × 1024 floats × 4 bytes = ~8 MB
316
316
  - `_index_document` / `_index_pdf_incremental` — IDs, documents, metadatas lists: ~5-10 MB
317
317
  - **Peak concurrent**: ~20-30 MB for the 771-page book (extraction + chunks + embeddings all in memory simultaneously before the first upsert)
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: "Chunk Boundary Equation Splitting — Information Loss at Chunk Boundaries"
3
+ id: RDR-054
4
+ type: Bug
5
+ status: closed
6
+ close_reason: implemented
7
+ closed_date: 2026-04-07
8
+ priority: high
9
+ author: Hal Hildebrand
10
+ reviewed-by: self
11
+ created: 2026-04-07
12
+ accepted_date: 2026-04-07
13
+ related_issues: []
14
+ ---
15
+
16
+ # RDR-054: Chunk Boundary Equation Splitting — Information Loss at Chunk Boundaries
17
+
18
+ > Revise during planning; lock at implementation.
19
+ > If wrong, abandon code and iterate RDR.
20
+
21
+ ## Problem Statement
22
+
23
+ When indexing PDF papers with mathematical equations, the chunker splits equation definitions across chunk boundaries such that:
24
+ - Chunk N ends with the prose leading to the definition (e.g., "The sigmoid excitatory feedback signal: f_u(u_ij) =")
25
+ - Chunk N+1 starts with the formula body, WITHOUT the variable name from Chunk N
26
+
27
+ This makes the formula **unsearchable by its variable name**. Searching for "f_u" finds Chunk N (truncated before the formula). Searching for the formula content finds Chunk N+1 but without context about what function it defines.
28
+
29
+ ### Reproduction
30
+
31
+ - Paper: GnaGroSovereign2007.pdf (109 pages, 537 chunks, MinerU extractor)
32
+ - Section: Appendix A4.5, Eq.56 (page 88)
33
+ - Search: "sigmoid excitatory feedback signal f_u" → returns chunk ending before the formula
34
+ - Re-indexing with `--extractor mineru --force` produces identical truncation
35
+
36
+ The actual equation (from direct PDF read):
37
+ ```
38
+ f_u(u_ij) = α^N · ([u_ij]⁺)^N / (α^N + θ · ([u_ij]⁺)^N)
39
+ where α=1.7, N=5, θ=9.8
40
+ ```
41
+
42
+ ### Impact
43
+
44
+ - HIGH for mathematical/scientific papers where equation definitions are primary content
45
+ - The f_u function was a Hill sigmoid, NOT the ([u]⁺)² inferred from analogy. The inference was wrong — 3 independent lines of analogical evidence all pointed to the wrong answer because the actual definition was trapped in a chunk boundary.
46
+ - Multiple parameter values (D₁=18 vs assumed 1.0, S_j={1/6,1/3,1/2} vs assumed {1.0,0.75,0.5}) were also in this truncated region.
47
+ - 17 parallel agents across 4 rounds of deep research (851+ chunk searches) all failed to find this equation via T3 search. Only resolved by reading the PDF directly with the Read tool at the page number.
48
+
49
+ ## Proposed Mitigations
50
+
51
+ ### M1: Chunk overlap (recommended, general-purpose)
52
+
53
+ **Priority 1 (CRITICAL):** Wire SemanticMarkdownChunker's dead `overlap_chars` (165 chars) into `_split_large_section` which currently has zero overlap. Affects: `md_chunker.py` lines 288–309. Cost: +5-8% corpus-level (only split sections pay).
54
+
55
+ **Priority 2 (HIGH):** Increase PDFChunker overlap from 225→300 chars (15%→20%). Affects: `pdf_chunker.py` line 12 (`_DEFAULT_OVERLAP`). Cost: +6.3% chunks (<$0.001/paper embedding).
56
+
57
+ **Migration cost:** Existing indexed documents retain old chunk boundaries until re-indexed. Full corpus re-indexing (`nx index pdf --force` per paper) required to benefit from the fix. For large corpora, estimate total embedding cost as documents × avg_chunks × embedding_price_per_token before running.
58
+
59
+ 300 chars covers all tested equation types including worst case (Long Boltzmann at 202 chars) for the overlap window. However, overlap only ensures the *leading context* is repeated — it does not prevent mid-equation splits for equations longer than the overlap window.
60
+
61
+ ### M2: Equation-aware chunking
62
+
63
+ Detect LaTeX equation environments (`\begin{equation}...\end{equation}`, `$$...$$`, `\tag{N}`) and ensure they are never split across chunks.
64
+
65
+ Affects: `pdf_chunker.py` primarily (LaTeX in extracted text).
66
+
67
+ Trade-off: requires equation boundary detection in extracted text, which varies by extractor. **Not yet verified:** whether MinerU output for GnaGroSovereign2007.pdf actually contains `$$`, `\begin{equation}`, or `\tag{N}` markers. If MinerU renders equations as plain text/Unicode, M2's LaTeX boundary detection has zero coverage. Needs an RF verifying the actual extraction format before implementing.
68
+
69
+ ### M3: Paragraph-boundary chunking
70
+
71
+ Split only at paragraph boundaries (double newline), never mid-paragraph. The f_u definition was mid-paragraph — M3 addresses this failure mode by construction.
72
+
73
+ Affects: `pdf_chunker.py` (sentence snapper could prefer `\n\n` over `. `), `md_chunker.py`.
74
+
75
+ Trade-off: may produce very large chunks for papers with long prose paragraphs. Needs a max-size fallback. However, scientific appendix equations are typically in short display-math paragraphs — paragraph length distribution in the reproduction document (GnaGroSovereign2007.pdf) should be measured to validate this concern. If equation-bearing paragraphs are short, M3 + max-size fallback may be simpler and more correct than overlap alone.
76
+
77
+ ### M4: Post-extraction equation linking
78
+
79
+ After chunking, scan for equation references (e.g., "Eq.56", "\tag{56}") and create cross-references between chunks that reference the same equation. Could use catalog links with `relates` type.
80
+
81
+ Affects: new module or extension to `link_generator.py`.
82
+
83
+ Trade-off: doesn't fix searchability — the equation is still split. But makes it discoverable via link traversal.
84
+
85
+ ## Recommendation
86
+
87
+ Start with M1 (chunk overlap) — md_chunker first (CRITICAL: currently zero overlap), then PDFChunker bump to 20%. M1 reduces the probability of context loss at boundaries but does not prevent mid-equation splits for equations longer than ~300 chars. M2 (equation-aware snapper) remains necessary for the elimination case.
88
+
89
+ M3 (paragraph boundaries) deserves evaluation alongside M1 for PDFChunker — it directly addresses the observed failure mode (mid-paragraph split). M4 is independent and complementary.
90
+
91
+ ## Key Discoveries
92
+
93
+ ### RF-1: Chunker boundary overlap audit (verified, source search)
94
+
95
+ Three distinct overlap gaps identified:
96
+
97
+ 1. **PDFChunker** (`pdf_chunker.py`): Has 225-char overlap (15% of 1500), but boundary snapper at lines 59–63 only looks for `. ` (period-space) — no awareness of LaTeX `$$...$$` or equation environments. Will split mid-equation if the equation doesn't end with a sentence period.
98
+
99
+ 2. **SemanticMarkdownChunker** (`md_chunker.py`): `_split_large_section()` at lines 261–323 has **zero overlap** between sub-chunks. The `chunk_overlap` / `overlap_chars` fields are defined but never used by the semantic path — dead code. Only the naive fallback path has overlap (165 chars). This is the most significant gap.
100
+
101
+ 3. **`_enforce_byte_cap`** (`chunker.py:163–211`): Sub-splits of oversized AST nodes also have zero overlap between sub-chunks. Lower priority since code chunking uses AST boundaries.
102
+
103
+ **Insertion points for fix:**
104
+ - `md_chunker.py:288–309`: Before `chunks.append(...)` at line 288, capture `emitted_text = "\n\n".join(current_parts)`. After the flush, prepend `emitted_text[-overlap_chars:]` to the new `current_parts` (after the header, so section context is preserved). The naive fallback path at lines 354–376 is a working reference implementation — same overlap structure, already tested.
105
+ - `pdf_chunker.py:59–63`: Extend snapper to check for unclosed `$$` in candidate window
106
+
107
+ ### RF-2: Prior art — RAG chunking overlap and equation-aware splitting (verified, source search)
108
+
109
+ No mainstream chunking library has equation/math-aware splitting (verified across LlamaIndex, LangChain, Unstructured, Chonkie, semchunk). Default overlaps: LlamaIndex SentenceSplitter ~19.5%, LangChain 200 chars (5%), Unstructured 0. Literature consensus: 10-20% optimal (NVIDIA FinanceBench). Nexus PDFChunker at 15% is already in range — the bug is the sentence snapper and the dead md_chunker overlap code. Equation-boundary snapping would be novel.
110
+
111
+ ### RF-3: Storage cost analysis — overlap overhead measured empirically (verified, spike)
112
+
113
+ PDFChunker 225→300 chars: +6.3% chunks, <$0.001/paper. 450 chars (doubled): +21.7% — excessive. md_chunker wiring 165ch overlap: +5-8% corpus-level. 200 chars is NOT enough for multi-line equations (Long Boltzmann at 202ch). 300 chars covers all tested types with margin. md_chunker overlap is CRITICAL priority (currently zero).
114
+
115
+ ## Finalization Gate
116
+
117
+ - [x] Overlap size determined: 300 chars PDFChunker, 165 chars md_chunker (RF-3)
118
+ - [x] Storage overhead measured: +6.3% PDF, +5-8% md corpus-level (RF-3)
119
+ - [ ] Impact validated against real-world corpus (post-implementation)
120
+ - [ ] No regression in existing chunker tests (post-implementation)
121
+ - [ ] Search recall improvement measured for boundary-split cases (post-implementation)
122
+ - [ ] MinerU extraction format verified for equation markers (RF needed for M2)
123
+
124
+ ## Revision History
125
+
126
+ - 2026-04-07: Gate PASSED. 2 criticals resolved in-gate (insertion point corrected, overlap limitation acknowledged), 3 significants addressed (migration cost, M3 evaluation, M2 feasibility).
127
+ - 2026-04-07: RF-1 (code audit), RF-2 (prior art), RF-3 (cost analysis) — all verified.
128
+ - 2026-04-07: Created from T2 issue report (nexus_issues/chunker-splits-equations-at-boundary). Source: RDR-068 research session where 17 parallel agents failed to find f_u equation definition.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "Self-hosted three-tier knowledge management with specialized agents, analytical query pipelines, semantic search, and RDR decision tracking for Claude Code.",
5
5
  "author": {
6
6
  "name": "Hal Hildebrand",
@@ -6,6 +6,14 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.2.4] - 2026-04-07
10
+
11
+ Plugin version aligned with Nexus CLI 3.2.4. No plugin-level functional changes.
12
+
13
+ ## [3.2.3] - 2026-04-07
14
+
15
+ Plugin version aligned with Nexus CLI 3.2.3. No plugin-level functional changes.
16
+
9
17
  ## [3.2.2] - 2026-04-07
10
18
 
11
19
  ### Fixed
@@ -109,6 +109,9 @@ T3 knowledge — permanent, semantic search:
109
109
  store_get(doc_id="...", collection="knowledge")
110
110
  Tool: mcp__plugin_nx_nexus__store_put
111
111
  store_put(content="...", collection="knowledge", title="...", tags="...")
112
+ AUTO-LINKING: store_put checks T1 scratch for link-context (tag: "link-context") and auto-creates catalog links.
113
+ If no link-context in scratch, self-seed: catalog_search your task references → scratch put with targets.
114
+ You MUST call store_put before returning — findings not stored are findings lost.
112
115
  Tool: mcp__plugin_nx_nexus__store_delete
113
116
  store_delete(doc_id="...", collection="knowledge")
114
117
  Tool: mcp__plugin_nx_nexus__collection_list
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "conexus"
7
- version = "3.2.2"
7
+ version = "3.2.4"
8
8
  description = "Self-hosted semantic search and knowledge management for LLM-driven development"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.12,<3.14"
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "sn",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
4
4
  "description": "Injects Serena and Context7 MCP tool usage guidance into subagents via SubagentStart hook."
5
5
  }
@@ -300,23 +300,27 @@ def setup_cmd(remote: str) -> None:
300
300
  @click.option("--owner", default="")
301
301
  @click.option("--type", "content_type", default="")
302
302
  @click.option("--limit", "-n", default=50)
303
+ @click.option("--offset", default=0)
303
304
  @click.option("--json", "as_json", is_flag=True)
304
- def list_cmd(owner: str, content_type: str, limit: int, as_json: bool) -> None:
305
+ def list_cmd(owner: str, content_type: str, limit: int, offset: int, as_json: bool) -> None:
305
306
  """List catalog entries."""
306
307
  cat = _get_catalog()
307
308
  if owner:
308
309
  entries = cat.by_owner(Tumbler.parse(owner))
309
310
  else:
310
- entries = cat.all_documents(limit=limit)
311
+ entries = cat.all_documents(limit=limit + offset + 1)
311
312
  if content_type:
312
313
  entries = [e for e in entries if e.content_type == content_type]
313
- entries = entries[:limit]
314
+ total = len(entries)
315
+ entries = entries[offset:offset + limit]
314
316
 
315
317
  if as_json:
316
318
  click.echo(json.dumps([_entry_to_dict(e) for e in entries], indent=2))
317
319
  else:
318
320
  for e in entries:
319
321
  click.echo(f"{str(e.tumbler):<12} {e.content_type:<10} {e.title}")
322
+ if offset + limit < total:
323
+ click.echo(f"\n Next page: --offset {offset + limit}")
320
324
 
321
325
 
322
326
  @catalog.command("show")
@@ -378,15 +382,18 @@ def show_cmd(tumbler_or_title: str, as_json: bool) -> None:
378
382
  @catalog.command("search")
379
383
  @click.argument("query")
380
384
  @click.option("--limit", "-n", default=20)
385
+ @click.option("--offset", default=0)
381
386
  @click.option("--json", "as_json", is_flag=True)
382
- def search_cmd(query: str, limit: int, as_json: bool) -> None:
387
+ def search_cmd(query: str, limit: int, offset: int, as_json: bool) -> None:
383
388
  """Find documents by title, author, corpus, or file path.
384
389
 
385
390
  Uses full-text search across document metadata. Faster than T3 semantic
386
391
  search for exact metadata lookups. Returns tumbler, type, and title.
387
392
  """
388
393
  cat = _get_catalog()
389
- results = cat.find(query)[:limit]
394
+ all_results = cat.find(query)
395
+ total = len(all_results)
396
+ results = all_results[offset:offset + limit]
390
397
  if as_json:
391
398
  click.echo(json.dumps([_entry_to_dict(e) for e in results], indent=2))
392
399
  else:
@@ -395,6 +402,8 @@ def search_cmd(query: str, limit: int, as_json: bool) -> None:
395
402
  return
396
403
  for e in results:
397
404
  click.echo(f"{str(e.tumbler):<12} {e.content_type:<10} {e.title}")
405
+ if offset + limit < total:
406
+ click.echo(f"\n Next page: --offset {offset + limit}")
398
407
 
399
408
 
400
409
  @catalog.command("register", hidden=True)
@@ -599,8 +608,10 @@ def links_cmd(
599
608
  links = cat.link_query(
600
609
  from_t=resolved_from, to_t=resolved_to,
601
610
  link_type=link_type, created_by=created_by,
602
- limit=limit, offset=offset,
611
+ limit=limit + 1, offset=offset,
603
612
  )
613
+ has_more = len(links) > limit
614
+ links = links[:limit]
604
615
  if as_json:
605
616
  click.echo(json.dumps([_link_to_dict(lnk) for lnk in links], indent=2))
606
617
  else:
@@ -609,6 +620,8 @@ def links_cmd(
609
620
  return
610
621
  for edge in links:
611
622
  click.echo(f"{edge.from_tumbler} → {edge.to_tumbler} ({edge.link_type}) by {edge.created_by}")
623
+ if has_more:
624
+ click.echo(f"\n Next page: --offset {offset + limit}")
612
625
 
613
626
 
614
627
  @catalog.command("link-bulk-delete", hidden=True)
@@ -391,6 +391,9 @@ def query(
391
391
  ) -> str:
392
392
  """Document-level semantic search for analytical questions.
393
393
 
394
+ Results are capped at ``limit``. When more documents match, a footer line shows
395
+ the total count. Increase ``limit`` to see more.
396
+
394
397
  Unlike ``search`` which returns individual chunks, ``query`` groups results
395
398
  by source document and returns the best-matching snippet per document along
396
399
  with full metadata (title, year, citations, page count, extraction method).
@@ -558,7 +561,9 @@ def query(
558
561
  docs[doc_key]["snippet"] = r.content[:300].replace("\n", " ")
559
562
 
560
563
  # Sort by best match distance, limit
561
- sorted_docs = sorted(docs.values(), key=lambda d: d["distance"])[:limit]
564
+ all_docs = sorted(docs.values(), key=lambda d: d["distance"])
565
+ sorted_docs = all_docs[:limit]
566
+ total = len(all_docs)
562
567
 
563
568
  header = f"Found {len(sorted_docs)} documents (from {len(results)} chunks across {len(target)} collections)"
564
569
  lines: list[str] = [f"{routing_note}\n{header}" if routing_note else header]
@@ -598,6 +603,9 @@ def query(
598
603
  lines.append(f" {d['snippet']}")
599
604
  lines.append("")
600
605
 
606
+ if total > limit:
607
+ lines.append(f"\n--- showing 1-{len(sorted_docs)} of {total} documents. Results are capped at limit={limit}.")
608
+
601
609
  return "\n".join(lines)
602
610
  except Exception as e:
603
611
  return f"Error: {e}"
@@ -936,6 +944,9 @@ def scratch(
936
944
  ) -> str:
937
945
  """T1 session scratch pad — ephemeral within-session storage.
938
946
 
947
+ For ``search`` and ``list``, results are capped at ``limit``. A footer
948
+ indicates when more entries exist.
949
+
939
950
  Args:
940
951
  action: One of "put", "search", "list", "get", "delete"
941
952
  content: Content to store (for "put")
@@ -964,17 +975,23 @@ def scratch(
964
975
  for r in results:
965
976
  snippet = r["content"][:200].replace("\n", " ")
966
977
  lines.append(f"{prefix}[{r['id'][:12]}] {snippet}")
978
+ if len(results) >= limit:
979
+ lines.append(f"\n--- showing {len(results)} results (limit={limit}). Increase limit to see more.")
967
980
  return "\n".join(lines)
968
981
 
969
982
  elif action == "list":
970
983
  entries = t1.list_entries()
971
984
  if not entries:
972
985
  return f"{prefix}No scratch entries."
986
+ total = len(entries)
987
+ entries = entries[:limit]
973
988
  lines = []
974
989
  for e in entries:
975
990
  snippet = e["content"][:80].replace("\n", " ")
976
991
  tags_str = f" [{e.get('tags', '')}]" if e.get("tags") else ""
977
992
  lines.append(f"{prefix}[{e['id'][:12]}] {snippet}{tags_str}")
993
+ if total > limit:
994
+ lines.append(f"\n--- showing {limit} of {total} entries. Increase limit to see all.")
978
995
  return "\n".join(lines)
979
996
 
980
997
  elif action == "get":
@@ -1159,17 +1176,25 @@ def plan_save(
1159
1176
 
1160
1177
 
1161
1178
  @mcp.tool()
1162
- def plan_search(query: str, project: str = "", limit: int = 5) -> str:
1179
+ def plan_search(query: str, project: str = "", limit: int = 5, offset: int = 0) -> str:
1163
1180
  """Search the T2 plan library for similar query plans.
1164
1181
 
1182
+ Results are paged. Response footer shows ``offset=N`` for next page.
1183
+
1165
1184
  Args:
1166
1185
  query: Search query (matched against plan query text and tags)
1167
1186
  project: Optional project filter (e.g. "nexus")
1168
- limit: Maximum results to return
1187
+ limit: Maximum results to return (default 5)
1188
+ offset: Skip this many results (default 0). Use for pagination.
1169
1189
  """
1170
1190
  try:
1171
1191
  with _t2_ctx() as db:
1172
- results = db.search_plans(query, limit=limit, project=project)
1192
+ # Over-fetch by 1 to detect if there are more
1193
+ results = db.search_plans(query, limit=limit + 1, project=project)
1194
+ if offset:
1195
+ results = results[offset:]
1196
+ has_more = len(results) > limit
1197
+ results = results[:limit]
1173
1198
  if not results:
1174
1199
  return "No matching plans."
1175
1200
  lines: list[str] = []
@@ -1180,6 +1205,9 @@ def plan_search(query: str, project: str = "", limit: int = 5) -> str:
1180
1205
  f" outcome={r['outcome']} tags={r['tags']}\n"
1181
1206
  f" plan: {plan_preview}..."
1182
1207
  )
1208
+ shown_end = offset + len(results)
1209
+ if has_more:
1210
+ lines.append(f"\n--- showing {offset + 1}-{shown_end}. may have more: offset={shown_end}")
1183
1211
  return "\n\n".join(lines)
1184
1212
  except Exception as e:
1185
1213
  return f"Error: {e}"
@@ -1205,11 +1233,15 @@ def catalog_search(
1205
1233
  owner: str = "",
1206
1234
  file_path: str = "",
1207
1235
  limit: int = 20,
1236
+ offset: int = 0,
1208
1237
  ) -> list[dict]:
1209
1238
  """Find documents by metadata (title, author, corpus, file path).
1210
1239
 
1240
+ Results are paged. When results are truncated, a ``_pagination`` entry appears
1241
+ at the end with ``next_offset``. Pass that value as ``offset`` to get the next page.
1242
+
1211
1243
  Returns catalog entries with tumbler, physical_collection, and metadata — NOT document
1212
- content. Use the `search` tool for semantic content search within collections.
1244
+ content. Use the ``search`` tool for semantic content search within collections.
1213
1245
  Use catalog_search first to discover WHICH collections to search, then search for content.
1214
1246
 
1215
1247
  Filters: query (free-text), author, corpus, owner, file_path, content_type (exact match).
@@ -1246,9 +1278,9 @@ def catalog_search(
1246
1278
  sql = (
1247
1279
  "SELECT tumbler, title, author, year, content_type, file_path, "
1248
1280
  "corpus, physical_collection, chunk_count, head_hash, indexed_at, metadata "
1249
- f"FROM documents WHERE {' AND '.join(conditions)} LIMIT ?"
1281
+ f"FROM documents WHERE {' AND '.join(conditions)} LIMIT ? OFFSET ?"
1250
1282
  )
1251
- params.append(limit)
1283
+ params.extend([limit + 1, offset])
1252
1284
  rows = cat._db.execute(sql, params).fetchall()
1253
1285
  from nexus.catalog.catalog import CatalogEntry
1254
1286
  entries = [
@@ -1260,7 +1292,12 @@ def catalog_search(
1260
1292
  )
1261
1293
  for r in rows
1262
1294
  ]
1263
- return [_entry_to_dict(e) for e in entries]
1295
+ has_more = len(entries) > limit
1296
+ entries = entries[:limit]
1297
+ result = [_entry_to_dict(e) for e in entries]
1298
+ if has_more:
1299
+ result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
1300
+ return result
1264
1301
 
1265
1302
  # FTS5 free-text search (append author to query if both provided)
1266
1303
  fts_query = query
@@ -1268,8 +1305,12 @@ def catalog_search(
1268
1305
  fts_query = f"{query} {author}"
1269
1306
  if not fts_query.strip():
1270
1307
  return [{"error": "query or at least one filter required"}]
1271
- results = cat.find(fts_query, content_type=content_type or None)[:limit]
1272
- return [_entry_to_dict(e) for e in results]
1308
+ all_results = cat.find(fts_query, content_type=content_type or None)
1309
+ page = all_results[offset:offset + limit]
1310
+ result = [_entry_to_dict(e) for e in page]
1311
+ if offset + limit < len(all_results):
1312
+ result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
1313
+ return result
1273
1314
  except Exception as e:
1274
1315
  return [{"error": str(e)}]
1275
1316
 
@@ -1315,7 +1356,10 @@ def catalog_list(
1315
1356
  limit: int = 50,
1316
1357
  offset: int = 0,
1317
1358
  ) -> list[dict]:
1318
- """List catalog entries with optional filters."""
1359
+ """List catalog entries with optional filters.
1360
+
1361
+ Results are paged. When truncated, a ``_pagination`` entry appears at the end
1362
+ with ``next_offset``. Pass that as ``offset`` to get the next page."""
1319
1363
  cat, err = _require_catalog()
1320
1364
  if err:
1321
1365
  return [{"error": err}]
@@ -1347,7 +1391,11 @@ def catalog_list(
1347
1391
  ]
1348
1392
  if content_type:
1349
1393
  entries = [e for e in entries if e.content_type == content_type]
1350
- return [_entry_to_dict(e) for e in entries[:limit]]
1394
+ page = entries[:limit]
1395
+ result = [_entry_to_dict(e) for e in page]
1396
+ if len(entries) > limit:
1397
+ result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
1398
+ return result
1351
1399
  except Exception as e:
1352
1400
  return [{"error": str(e)}]
1353
1401
 
@@ -1592,6 +1640,9 @@ def catalog_link_query(
1592
1640
  ) -> list[dict]:
1593
1641
  """Query links by any combination of filters. For admin/audit use.
1594
1642
 
1643
+ Results are paged. When truncated, a ``_pagination`` entry appears at the end
1644
+ with ``next_offset``. Pass that as ``offset`` to get the next page.
1645
+
1595
1646
  NOT a query-planner step — use catalog_links for graph traversal.
1596
1647
  Use for: audit by creator, find all links of a type, count generator output.
1597
1648
  created_at_before: ISO timestamp — only links created before this time.
@@ -1606,9 +1657,14 @@ def catalog_link_query(
1606
1657
  from_t=from_tumbler, to_t=to_tumbler, link_type=link_type,
1607
1658
  created_by=created_by, direction=direction, tumbler=tumbler,
1608
1659
  created_at_before=created_at_before,
1609
- limit=limit, offset=offset,
1660
+ limit=limit + 1, offset=offset,
1610
1661
  )
1611
- return [_link_to_dict(l) for l in links]
1662
+ has_more = len(links) > limit
1663
+ links = links[:limit]
1664
+ result = [_link_to_dict(l) for l in links]
1665
+ if has_more:
1666
+ result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
1667
+ return result
1612
1668
  except Exception as e:
1613
1669
  return [{"error": str(e)}]
1614
1670
 
@@ -284,10 +284,18 @@ class SemanticMarkdownChunker:
284
284
  current_tokens += part_tokens
285
285
  current_end_char = part_end_char
286
286
  else:
287
+ is_code = part.get("is_code_block", False)
288
+ if self.preserve_code_blocks and is_code:
289
+ # Emit code blocks atomically — never truncate, even if oversized.
290
+ pass
291
+ elif len(part_text) > self.max_chars:
292
+ # Truncate oversized non-code parts to prevent unbounded chunk sizes.
293
+ part_text = part_text[: self.max_chars]
287
294
  if current_parts:
295
+ emitted_text = "\n\n".join(current_parts)
288
296
  chunks.append(
289
297
  self._make_chunk(
290
- "\n\n".join(current_parts),
298
+ emitted_text,
291
299
  chunk_index,
292
300
  base_metadata,
293
301
  section["header_path"],
@@ -297,16 +305,21 @@ class SemanticMarkdownChunker:
297
305
  )
298
306
  chunk_index += 1
299
307
  section_start_char = current_end_char
300
- is_code = part.get("is_code_block", False)
301
- if self.preserve_code_blocks and is_code:
302
- # Emit code blocks atomically never truncate, even if oversized.
303
- pass
304
- elif len(part_text) > self.max_chars:
305
- # Truncate oversized non-code parts to prevent unbounded chunk sizes.
306
- part_text = part_text[: self.max_chars]
307
- header_tokens = len(header_text) / _CHARS_PER_TOKEN if header_text else 0.0
308
- current_parts = [header_text, part_text] if header_text else [part_text]
309
- current_tokens = header_tokens + len(part_text) / _CHARS_PER_TOKEN
308
+ if self.overlap_chars > 0:
309
+ # Compute overlap from content only (skip header) to
310
+ # avoid duplicating the header when emitted_text is
311
+ # shorter than overlap_chars.
312
+ content_text = "\n\n".join(current_parts[1:]) if header_text else emitted_text
313
+ overlap_tail = content_text[-self.overlap_chars:] if content_text else ""
314
+ if header_text:
315
+ current_parts = [header_text, overlap_tail, part_text]
316
+ else:
317
+ current_parts = [overlap_tail, part_text]
318
+ else:
319
+ current_parts = [header_text, part_text] if header_text else [part_text]
320
+ else:
321
+ current_parts = [header_text, part_text] if header_text else [part_text]
322
+ current_tokens = sum(len(p) for p in current_parts) / _CHARS_PER_TOKEN
310
323
  current_end_char = part_end_char
311
324
 
312
325
  if current_parts: