conexus 6.2.0__tar.gz → 6.3.0__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.
- {conexus-6.2.0 → conexus-6.3.0}/PKG-INFO +1 -1
- {conexus-6.2.0 → conexus-6.3.0}/mcpb/pyproject.toml +2 -2
- {conexus-6.2.0 → conexus-6.3.0}/pyproject.toml +1 -1
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/CatalogRepository.java +50 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/ChashRepository.java +81 -15
- conexus-6.3.0/service/src/main/java/dev/nexus/service/db/CollectionRegistry.java +104 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TenantScope.java +85 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TokenCache.java +12 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/AspectHandler.java +8 -21
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/CatalogHandler.java +4 -16
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/ChashHandler.java +7 -2
- conexus-6.3.0/service/src/main/java/dev/nexus/service/http/HttpUtil.java +159 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/MemoryHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/PlanHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/ScratchHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/SessionTokenHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/TaxonomyHandler.java +4 -13
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/TelemetryHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/TokenAdminHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/VectorHandler.java +7 -2
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/PgVectorRepository.java +92 -34
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/BridgeAddressFieldsTest.java +4 -4
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogDeleteCollectionCascadeTest.java +6 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogRenameCollectionTest.java +7 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogRepositoryTest.java +30 -0
- conexus-6.3.0/service/src/test/java/dev/nexus/service/ChashVectorConcurrencyTest.java +367 -0
- conexus-6.3.0/service/src/test/java/dev/nexus/service/db/CollectionRegistryTest.java +328 -0
- conexus-6.3.0/service/src/test/java/dev/nexus/service/db/TenantScopeAdmissionTest.java +179 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/http_catalog_client.py +114 -16
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/scratch.py +47 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/binary_install.py +1 -1
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/__init__.py +56 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/http_scratch_store.py +17 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/http_vector_client.py +421 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t1.py +9 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc_indexer.py +81 -4
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp_infra.py +27 -3
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/scoring.py +24 -11
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/search_engine.py +46 -3
- conexus-6.2.0/service/src/main/java/dev/nexus/service/http/HttpUtil.java +0 -87
- {conexus-6.2.0 → conexus-6.3.0}/.beads/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/.gitignore +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/LICENSE +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/agents/_shared/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/daemon/com.nexus.service.plist +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/daemon/com.nexus.t2.plist +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/daemon/com.nexus.t3.plist +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/daemon/nexus-service.service +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/daemon/nexus-t2.service +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/daemon/nexus-t3.service +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/hooks/scripts/routing/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/abstract-themes.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/analyze-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/citation-traversal.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/debug-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/document-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/find-by-author.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/hybrid-factual-lookup.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/plan-author-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/plan-inspect-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/plan-inspect-dimensions.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/plan-promote-propose.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/research-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/review-default.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/traverse-then-generate.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/builtin/type-scoped-search.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/dimensions.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/conexus/plans/purposes.yml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/data/calibration/rdr-109/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/docs/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/docs/migration/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/docs/rdr/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/dt/scripts/Index Current Group in nx.applescript +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/dt/scripts/Index Selection in nx (Knowledge).applescript +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/dt/scripts/Index Selection in nx.applescript +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/mcpb/src/server.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/cron/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/launchd/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/rdr152-sandbox/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/spikes/s04-build/src/main/java/dev/nexus/spike/s04/Main.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/spikes/s04-build/src/main/resources/META-INF/native-image/reachability-metadata.json +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/spikes/s04-build/src/main/resources/db/changelog/db.changelog-master.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/scripts/spikes/s04-build/src/main/resources/logback.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/Main.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/NexusService.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/AspectRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/MemoryRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/MigrationJobRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/PlanRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/PoolerModeCheck.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/SchemaMigrator.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/ScratchRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/SessionPrincipal.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TaxonomyRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TelemetryRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TenantConstants.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TokenHashing.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/TokenStore.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/AuthFilter.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/HealthHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/MigrationHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/RequestContext.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/VersionHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/WhoamiHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/nativeimage/JooqRecordReflectionFeature.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/ChromaSchemeHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/ChunkTextFetcher.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/HttpsSchemeHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/ResolveResult.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/UnknownSchemeException.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/UriSchemeHandler.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/resolver/UriSchemeResolverRegistry.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/Bge768Embedder.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/CceEmbedder.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/ChromaQuotaValidator.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/ChromaRestClient.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/EgressProxy.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/EmbedResult.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/Embedder.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/EmbedderRouter.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/EmbeddingModelUnavailableException.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/LocalChromaServer.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/OnnxEmbedder.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/TaxonomyCentroidRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/VectorRepository.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/vectors/VoyageEmbedder.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/META-INF/native-image/native-image.properties +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/META-INF/native-image/reflect-config.json +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/META-INF/native-image/resource-config.json +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/META-INF/native-image/traced/reachability-metadata.json +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/META-INF/nexus/release.properties +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/aspects-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/aspects-002-next-retry-at.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-002-hygiene.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-003-soft-delete.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-004-manifest-functions.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-005-collection-vector-stats.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-006-combined-query-functions.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-007-graph-hop-functions.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-008-combined-query-extensions.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-009-read-shape-views.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/catalog-011-collection-health-stale-age.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/chash-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/db.changelog-master.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/fk-001-catalog-cross-store.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/fk-002-collection-registry.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/fk-002-validate.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/fk-003-collection-registry-extra.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/fk-003-validate.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/grants-nexus-svc.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/memory-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/migration-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/perf-001-rename-collection-indexes.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/plans-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/role-001-nexus-svc.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/service-tokens-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/service-tokens-002-single-root-index.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/t1-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/taxonomy-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/taxonomy-002-centroids.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/taxonomy-003-doc-count-trigger.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/taxonomy-004-dedup-root-topics.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/telemetry-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/updated-at-001-triggers.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/vectors-001-baseline.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/db/changelog/vectors-002-trgm-index.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/main/resources/logback.xml +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/AspectOperatorQueryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/AspectRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/AuthFilterTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/Bge768ParityTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/Bge768ServiceEmbedIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogDocumentCascadeTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogHandlerDeleteTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogHandlerRenameTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CatalogSchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ChashRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ChunksRlsBehavioralTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CollectionRegistryFkExtraTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CollectionRegistryFkTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CollectionVectorStatsTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CombinedQueryParityIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/CombinedQueryParityTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/DualRunHarnessIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/EmbedParityTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/EmbeddingModeFailLoudTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ForeignKeyConstraintTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/GraphHopParityIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/GraphHopParityTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/HybridParityIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/HybridSelectiveGateTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ManifestFunctionsTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/MemoryHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/MemoryRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/MemorySchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PgBouncerTenantIsolationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PgContainerHelper.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PgVectorCombinedQueryContractTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PgVectorHybridSearchContractTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PgVectorRepositoryContractTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PgVectorServingContractTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PlanHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PlanRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/PlansSchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ReadShapeViewsTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ReferenceOnlyChunkUpsertTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/SchemaMigratorIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ScratchHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ScratchRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ScratchSchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ServiceBindHostTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ServiceIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/ServiceTokenSchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/SessionTokenHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/SoftDeleteTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TaxonomyCentroidHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TaxonomyCentroidRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TaxonomyCentroidSchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TaxonomyPersistHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TaxonomyRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TaxonomySchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TelemetryRepositoryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TelemetrySchemaLiquibaseTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TenantPoolingIsolationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TokenAdminHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/TokenBoundaryAdversarialTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/UpdatedAtTriggerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/VectorHandlerEmbeddingModeTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/VectorHandlerTokenUsageTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/VectorHybridHttpTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/VectorIntegrationTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/db/PoolerModeCheckTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/db/TenantScopeGucAllowlistTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/http/AspectHandlerEnqueueErrorTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/http/CatalogHandlerImportEmptyBodyTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/http/CatalogHandlerManifestFkTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/http/MigrationHandlerIngestCloudTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/http/TaxonomyHandlerAssignFkTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/http/VersionHandlerReleaseVersionTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/nativeimage/JooqRecordReflectionFeatureTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/resolver/ChromaSchemeHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/resolver/HttpsSchemeHandlerTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/resolver/UriSchemeResolverRegistryTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/vectors/Bge768EmbedderMathTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/vectors/EgressProxyTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/vectors/EmbedderRouterBge768Test.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/vectors/EmbedderRouterVoyageOnlyTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/vectors/PgVectorRepositoryWherePredicateTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/java/dev/nexus/service/vectors/ReferenceOnlySqlShapeTest.java +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/service/src/test/resources/bge768/parity_reference.json +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/sn/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/sn/hooks/scripts/routing/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/_git_hooks_meta.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/_locking.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/_mineru_pid.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/_session_end_launcher.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/aspect_extractor.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/aspect_promotion.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/aspect_readers.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/aspect_worker.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/bib_enricher.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/bib_enricher_openalex.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/bib_extractor.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/AGENTS.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/auto_linker.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_backup.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_db.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_docs.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_git.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_links.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_owners.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_protocol.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_spans.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_sync.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/catalog_writes.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/collection_name.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/collections_owner_backfill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/consolidation.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/dedupe.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/dt_link_generator.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/event_log.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/events.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/factory.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/link_generator.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/manifest_backfill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/orphan_backfill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/projector.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/store_hook.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/synthesizer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/tumbler.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/types.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/catalog/write_priority.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/checkpoint.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/chunk_identity.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/chunker.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/classifier.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/cli.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/code_indexer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/collection_audit.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/collection_health.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/collection_rename.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/_helpers.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/_migration_prompt.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/_provision.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/aspects.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/backfill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/backups.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/collections.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/doctor.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/integrity.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/links.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/maintenance.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/migration.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/orphan_backfill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/owners.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/remediation.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/catalog_cmds/report.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/collection.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/command_context.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/config_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/console.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/context_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/daemon.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/doc.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/doctor.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/dt.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/enrich.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/guided_upgrade_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/hook.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/hooks.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/index.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/init.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/memory.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/migrate_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/migration_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/mineru.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/plan.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/rdr.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/search_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/service_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/storage_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/t3.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/taxonomy_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/tenant_cmd.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/tier_status.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/uninstall.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/commands/upgrade.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/config.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/app.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/config.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/routes/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/routes/activity.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/routes/campaigns.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/routes/health.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/routes/partials.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/static/alpine.min.js +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/static/console.css +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/static/htmx.min.js +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/static/pico.min.css +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/activity/_detail.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/activity/_stream.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/activity/index.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/base.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/campaigns/detail.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/campaigns/index.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/health/_cards.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/templates/health/index.html +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/console/watchers.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/context.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/corpus.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/cross_encoder.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/AGENTS.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/T2_DAEMON_WIP.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/aspect_worker_daemon.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/binary_lifecycle.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/catalog_write_shim.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/discovery.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/installer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/service_registry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/spin_guard.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/storage_service_daemon.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/t1_lease.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/t2_client.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/t2_daemon.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/daemon/t3_daemon.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/AGENTS.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/chroma_quotas.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/collection_purge.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/embed_migrate.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/local_ef.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/managed_endpoint.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/migrations.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/pg_bundle.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/pg_provision.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/service_bge_model.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/service_endpoint.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/storage_mode.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/_raw_handle_guard.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/_tuning.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/aspect_extraction_queue.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/aspects_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/catalog.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/catalog_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/catalog_taxonomy.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/chash_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/chash_index.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/document_aspects.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/document_highlights.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_aspect_queue.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_centroid_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_chash_index.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_document_aspects_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_document_highlights_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_memory_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_plan_library.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_taxonomy_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_telemetry_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/http_token_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/memory_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/memory_store.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/plan_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/plan_library.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/taxonomy_compute.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/taxonomy_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/telemetry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t2/telemetry_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t3.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/db/t3_reidentify.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/devonthink.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/_common.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/citations.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/ref_scanner.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/render.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/resolvers.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/resolvers_corpus.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doc/tokens.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/doctor_search.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/dropped_writes.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/dt_writeback.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/errors.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/exporter.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/filters.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/formatters.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/frecency.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/glossary.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/health.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/hook_registry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/hooks.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/index_context.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/indexer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/indexer_utils.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/languages.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/logging_setup.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/AGENTS.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/_first_run.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/_t1_state.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/catalog.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/core.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/devonthink.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp/plan_cache_registry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp_client/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp_client/core.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp_client/devonthink.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/mcp_server.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/md_chunker.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/merge_candidates.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/metadata_schema.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/banner.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/chroma_read.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/detection.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/driver.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/etl_registry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/guided_upgrade.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/manifest_check.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/migration_report.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/orchestrator.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/pregate.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/quiesce.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/route_coverage.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/sequencer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/state.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/validation.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/vector_etl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/migration/verify_fill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/name_canaries.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/operators/aspect_sql.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/operators/dispatch.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/pdeathsig.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/pdf_chunker.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/pdf_extractor.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/phase_review_sentinel.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/pipeline_buffer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/pipeline_stages.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/bundle.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/loader.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/match.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/matcher.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/promote.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/purposes.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/repair.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/runner.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/schema.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/scope.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/seed_loader.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/plans/session_cache.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/prose_indexer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/registry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/repo_identity.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/repos.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/retry.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/ripgrep_cache.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/routing_stats.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/salience.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/search_clusterer.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/session.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/stage_timers.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/storage_boundary_lint.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/taxonomy.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/taxonomy_backfill.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/ttl.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/types.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/util/__init__.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/src/nexus/util/process_group.py +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/tests/cc-validation/README.md +0 -0
- {conexus-6.2.0 → conexus-6.3.0}/tests/e2e/t2-migration-sqlite/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conexus
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.3.0
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "conexus-mcpb"
|
|
3
|
-
version = "6.
|
|
3
|
+
version = "6.3.0"
|
|
4
4
|
description = "Conexus packaged as Claude Desktop .mcpb (Desktop Extension)"
|
|
5
5
|
requires-python = ">=3.12"
|
|
6
6
|
dependencies = [
|
|
@@ -10,7 +10,7 @@ dependencies = [
|
|
|
10
10
|
# while collections are indexed at 768/1024-dim, so every T3 search hits a
|
|
11
11
|
# dimension mismatch and returns zero results. The .mcpb cannot run the
|
|
12
12
|
# interactive `nx init` embedder choice, so it must pin [local] explicitly.
|
|
13
|
-
"conexus[local]>=6.
|
|
13
|
+
"conexus[local]>=6.3.0",
|
|
14
14
|
]
|
|
15
15
|
|
|
16
16
|
[tool.uv]
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "conexus"
|
|
7
|
-
version = "6.
|
|
7
|
+
version = "6.3.0"
|
|
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"
|
{conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/CatalogRepository.java
RENAMED
|
@@ -531,8 +531,35 @@ public final class CatalogRepository {
|
|
|
531
531
|
* Silently strips {@code deleted_at} from the input map — callers must use
|
|
532
532
|
* {@code document_trash} / {@code document_restore} to manage the tombstone column.
|
|
533
533
|
*/
|
|
534
|
+
/**
|
|
535
|
+
* Settable columns for {@link #updateDocument} (wave review, SQL audit CRITICAL):
|
|
536
|
+
* request JSON keys become SET targets via {@code DSL.field(DSL.name(...))}, so
|
|
537
|
+
* WITHOUT this whitelist any body key was an arbitrary-column write from
|
|
538
|
+
* {@code POST /v1/catalog/update} — including {@code tenant_id} (re-homing a
|
|
539
|
+
* document across tenants) and lifecycle columns like {@code created_at}.
|
|
540
|
+
* The set mirrors the local {@code Catalog.update} mutable surface
|
|
541
|
+
* ({@link #documentFields()} minus the identity/lifecycle columns:
|
|
542
|
+
* tumbler, tenant_id, deleted_at, created_at). Unknown keys fail loud with
|
|
543
|
+
* {@code IllegalArgumentException} → 400, never a silent skip.
|
|
544
|
+
*/
|
|
545
|
+
private static final Set<String> UPDATABLE_DOC_COLUMNS = Set.of(
|
|
546
|
+
"title", "author", "year", "content_type", "file_path", "corpus",
|
|
547
|
+
"physical_collection", "chunk_count", "head_hash", "indexed_at",
|
|
548
|
+
"meta", "metadata", "source_mtime", "alias_of", "source_uri",
|
|
549
|
+
"bib_year", "bib_authors", "bib_venue", "bib_citation_count",
|
|
550
|
+
"bib_semantic_scholar_id", "bib_openalex_id", "bib_doi", "bib_enriched_at");
|
|
551
|
+
|
|
534
552
|
public int updateDocument(String tenant, String tumbler, Map<String, Object> fields) {
|
|
535
553
|
if (fields.isEmpty()) return 0;
|
|
554
|
+
for (String key : fields.keySet()) {
|
|
555
|
+
// deleted_at keeps its documented silent-strip contract (callers must use
|
|
556
|
+
// trash/restore); every OTHER unknown key is a caller error — fail loud.
|
|
557
|
+
if (!"deleted_at".equals(key) && !UPDATABLE_DOC_COLUMNS.contains(key)) {
|
|
558
|
+
throw new IllegalArgumentException(
|
|
559
|
+
"updateDocument: column not updatable: '" + key
|
|
560
|
+
+ "' (allowed: " + UPDATABLE_DOC_COLUMNS + ")");
|
|
561
|
+
}
|
|
562
|
+
}
|
|
536
563
|
return tenantScope.withTenant(tenant, ctx -> {
|
|
537
564
|
var step = ctx.update(T_DOCS);
|
|
538
565
|
UpdateSetMoreStep<?> more = null;
|
|
@@ -1420,6 +1447,16 @@ public final class CatalogRepository {
|
|
|
1420
1447
|
* streaming buffer and the entire local-mode (sqlite/Chroma) cascade.
|
|
1421
1448
|
*/
|
|
1422
1449
|
public Map<String, Integer> deleteCollection(String tenant, String name) {
|
|
1450
|
+
Map<String, Integer> counts = deleteCollectionTxn(tenant, name);
|
|
1451
|
+
// Post-commit (nexus-h8rf6 wave review): the registry row is gone; a stale
|
|
1452
|
+
// CollectionRegistry entry would make later writers silently skip
|
|
1453
|
+
// re-registration if the name is reused. Same post-commit discipline as
|
|
1454
|
+
// markKnown — see CollectionRegistry.evict.
|
|
1455
|
+
CollectionRegistry.evict(tenant, name);
|
|
1456
|
+
return counts;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
private Map<String, Integer> deleteCollectionTxn(String tenant, String name) {
|
|
1423
1460
|
return tenantScope.withTenant(tenant, ctx -> {
|
|
1424
1461
|
Map<String, Integer> counts = new LinkedHashMap<>();
|
|
1425
1462
|
// 1. T3 chunk vectors (registry children, fk-002 RESTRICT).
|
|
@@ -1516,6 +1553,19 @@ public final class CatalogRepository {
|
|
|
1516
1553
|
* rows untouched — preserving pre-RDR-164 RDR-162 behavior.
|
|
1517
1554
|
*/
|
|
1518
1555
|
public Map<String, Integer> renameCollection(String tenant, String oldName, String newName) {
|
|
1556
|
+
Map<String, Integer> counts = renameCollectionTxn(tenant, oldName, newName);
|
|
1557
|
+
// Post-commit (nexus-h8rf6 wave review): the canonical branch DELETEs the
|
|
1558
|
+
// old registry row — evict it so a later same-named collection re-registers.
|
|
1559
|
+
// The cross-model COPY branch leaves both registry rows untouched (no key
|
|
1560
|
+
// in counts), so nothing is evicted there.
|
|
1561
|
+
if (counts.containsKey("catalog_collections_deleted")) {
|
|
1562
|
+
CollectionRegistry.evict(tenant, oldName);
|
|
1563
|
+
CollectionRegistry.markKnown(tenant, newName);
|
|
1564
|
+
}
|
|
1565
|
+
return counts;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
private Map<String, Integer> renameCollectionTxn(String tenant, String oldName, String newName) {
|
|
1519
1569
|
return tenantScope.withTenant(tenant, ctx -> {
|
|
1520
1570
|
Map<String, Integer> counts = new LinkedHashMap<>();
|
|
1521
1571
|
boolean targetExists = ctx.fetchExists(
|
{conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/db/ChashRepository.java
RENAMED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package dev.nexus.service.db;
|
|
2
2
|
|
|
3
3
|
import org.jooq.DSLContext;
|
|
4
|
+
|
|
5
|
+
import static dev.nexus.service.jooq.nexus.Tables.CATALOG_COLLECTIONS;
|
|
4
6
|
import org.jooq.Field;
|
|
5
7
|
import org.jooq.Record3;
|
|
6
8
|
import org.jooq.impl.DSL;
|
|
@@ -72,16 +74,71 @@ public final class ChashRepository {
|
|
|
72
74
|
* error — fail loud rather than silently skipping the registration step and letting the
|
|
73
75
|
* subsequent INSERT fail with a cryptic FK violation.
|
|
74
76
|
*
|
|
77
|
+
* <p>Bead nexus-h8rf6.2 (contention relief): skips the INSERT entirely when
|
|
78
|
+
* {@link CollectionRegistry} already knows this {@code (tenant, collection)} pair is
|
|
79
|
+
* registered. See {@link CollectionRegistry} class doc for why the repeated
|
|
80
|
+
* {@code ON CONFLICT DO NOTHING} was a same-row lock-wait convoy under concurrent
|
|
81
|
+
* indexing, and why callers (not this method) are responsible for marking the cache
|
|
82
|
+
* only after the enclosing transaction commits.
|
|
83
|
+
*
|
|
75
84
|
* @throws IllegalArgumentException if collection is null or blank
|
|
76
85
|
*/
|
|
77
86
|
private static void ensureCollectionRegistered(DSLContext ctx, String tenant, String collection) {
|
|
78
87
|
if (collection == null || collection.isBlank()) {
|
|
79
88
|
throw new IllegalArgumentException("physical_collection must not be blank");
|
|
80
89
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
if (CollectionRegistry.isKnown(tenant, collection)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
ctx.insertInto(CATALOG_COLLECTIONS,
|
|
94
|
+
CATALOG_COLLECTIONS.TENANT_ID, CATALOG_COLLECTIONS.NAME)
|
|
95
|
+
.values(tenant, collection)
|
|
96
|
+
.onConflict(CATALOG_COLLECTIONS.TENANT_ID, CATALOG_COLLECTIONS.NAME)
|
|
97
|
+
.doNothing()
|
|
98
|
+
.execute();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Register {@code collection} in its OWN short committed transaction, then mark
|
|
103
|
+
* the {@link CollectionRegistry} cache.
|
|
104
|
+
*
|
|
105
|
+
* <p>Bounded first-burst convoy (v0.1.21, ChashVectorConcurrencyTest full-suite
|
|
106
|
+
* failure): with registration inside the batch transaction, the FIRST writer to
|
|
107
|
+
* a brand-new collection holds the {@code catalog_collections} ON CONFLICT value
|
|
108
|
+
* lock for its ENTIRE batch — every concurrent racer blocks for the winner's
|
|
109
|
+
* whole batch duration, and on a loaded host that exceeds the pool's
|
|
110
|
+
* connectionTimeout, surfacing typed 503s the cache was built to prevent. The
|
|
111
|
+
* CollectionRegistry cache bounds convoy COUNT (one per process lifetime);
|
|
112
|
+
* this bounds convoy DURATION (a single-statement micro-transaction, committed
|
|
113
|
+
* before the batch begins).
|
|
114
|
+
*
|
|
115
|
+
* <p>Trade-off, accepted: if the subsequent batch rolls back, the stub row
|
|
116
|
+
* persists — a zero-chunk registry stub is benign (collection existence is
|
|
117
|
+
* live-chunk-count-based everywhere: {@code collection_exists}, {@code /stats};
|
|
118
|
+
* {@code deleteCollection} removes stubs) and the pre-registration is exactly
|
|
119
|
+
* what any retry would recreate. Batch paths use this; {@code renameCollection}
|
|
120
|
+
* keeps in-transaction {@link #ensureCollectionRegistered} because its
|
|
121
|
+
* registration must be atomic with the re-point.
|
|
122
|
+
*/
|
|
123
|
+
private void registerCollectionShortTxn(String tenant, String collection) {
|
|
124
|
+
if (collection == null || collection.isBlank()) {
|
|
125
|
+
throw new IllegalArgumentException("physical_collection must not be blank");
|
|
126
|
+
}
|
|
127
|
+
if (CollectionRegistry.isKnown(tenant, collection)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
tenantScope.withTenant(tenant, ctx -> {
|
|
131
|
+
ctx.insertInto(CATALOG_COLLECTIONS,
|
|
132
|
+
CATALOG_COLLECTIONS.TENANT_ID, CATALOG_COLLECTIONS.NAME)
|
|
133
|
+
.values(tenant, collection)
|
|
134
|
+
.onConflict(CATALOG_COLLECTIONS.TENANT_ID, CATALOG_COLLECTIONS.NAME)
|
|
135
|
+
.doNothing()
|
|
136
|
+
.execute();
|
|
137
|
+
return null;
|
|
138
|
+
});
|
|
139
|
+
// Post-commit discipline per CollectionRegistry class doc: the registration
|
|
140
|
+
// transaction above has committed by the time withTenant returns.
|
|
141
|
+
CollectionRegistry.markKnown(tenant, collection);
|
|
85
142
|
}
|
|
86
143
|
|
|
87
144
|
// ── upsert ─────────────────────────────────────────────────────────────────
|
|
@@ -100,9 +157,10 @@ public final class ChashRepository {
|
|
|
100
157
|
if (collection == null || collection.isBlank()) throw new IllegalArgumentException("collection must not be empty");
|
|
101
158
|
|
|
102
159
|
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
|
|
160
|
+
// Own short committed txn — bounds the first-registration convoy DURATION
|
|
161
|
+
// (see registerCollectionShortTxn doc); also handles markKnown post-commit.
|
|
162
|
+
registerCollectionShortTxn(tenant, collection);
|
|
103
163
|
tenantScope.withTenant(tenant, ctx -> {
|
|
104
|
-
// RDR-156 P0.2: ensure catalog_collections has a stub row before the chash write.
|
|
105
|
-
ensureCollectionRegistered(ctx, tenant, collection);
|
|
106
164
|
ctx.insertInto(CHASH_INDEX,
|
|
107
165
|
F_TENANT, F_CHASH, F_COLLECTION, F_CREATED_AT)
|
|
108
166
|
.values(tenant, chash, collection, now)
|
|
@@ -131,9 +189,10 @@ public final class ChashRepository {
|
|
|
131
189
|
.toList();
|
|
132
190
|
if (valid.isEmpty()) return;
|
|
133
191
|
|
|
192
|
+
// Own short committed txn — bounds the first-registration convoy DURATION
|
|
193
|
+
// (see registerCollectionShortTxn doc); also handles markKnown post-commit.
|
|
194
|
+
registerCollectionShortTxn(tenant, collection);
|
|
134
195
|
tenantScope.withTenant(tenant, ctx -> {
|
|
135
|
-
// RDR-156 P0.2: ensure catalog_collections has a stub row before the chash writes.
|
|
136
|
-
ensureCollectionRegistered(ctx, tenant, collection);
|
|
137
196
|
var insert = ctx.insertInto(CHASH_INDEX,
|
|
138
197
|
F_TENANT, F_CHASH, F_COLLECTION, F_CREATED_AT);
|
|
139
198
|
var step = insert.values(tenant, valid.get(0), collection, now);
|
|
@@ -221,7 +280,7 @@ public final class ChashRepository {
|
|
|
221
280
|
* via {@code withTenant}.
|
|
222
281
|
*/
|
|
223
282
|
public int renameCollection(String tenant, String oldCollection, String newCollection) {
|
|
224
|
-
|
|
283
|
+
int updated = tenantScope.withTenant(tenant, ctx -> {
|
|
225
284
|
// RDR-156 P0.2: ensure the new collection is registered before renaming.
|
|
226
285
|
ensureCollectionRegistered(ctx, tenant, newCollection);
|
|
227
286
|
// Drop rows in new that would collide with the rename
|
|
@@ -239,6 +298,9 @@ public final class ChashRepository {
|
|
|
239
298
|
.where(F_COLLECTION.eq(oldCollection))
|
|
240
299
|
.execute();
|
|
241
300
|
});
|
|
301
|
+
// Post-commit (nexus-h8rf6.2): see upsert()'s comment / CollectionRegistry doc.
|
|
302
|
+
CollectionRegistry.markKnown(tenant, newCollection);
|
|
303
|
+
return updated;
|
|
242
304
|
}
|
|
243
305
|
|
|
244
306
|
// ── delete_stale ───────────────────────────────────────────────────────────
|
|
@@ -351,9 +413,10 @@ public final class ChashRepository {
|
|
|
351
413
|
}
|
|
352
414
|
|
|
353
415
|
final OffsetDateTime ts = createdAt;
|
|
416
|
+
// Own short committed txn — bounds the first-registration convoy DURATION
|
|
417
|
+
// (see registerCollectionShortTxn doc); also handles markKnown post-commit.
|
|
418
|
+
registerCollectionShortTxn(tenant, collection);
|
|
354
419
|
tenantScope.withTenant(tenant, ctx -> {
|
|
355
|
-
// RDR-156 P0.2: ensure catalog_collections has a stub row before the chash write.
|
|
356
|
-
ensureCollectionRegistered(ctx, tenant, collection);
|
|
357
420
|
ctx.insertInto(CHASH_INDEX,
|
|
358
421
|
F_TENANT, F_CHASH, F_COLLECTION, F_CREATED_AT)
|
|
359
422
|
.values(tenant, chash, collection, ts)
|
|
@@ -405,11 +468,13 @@ public final class ChashRepository {
|
|
|
405
468
|
}
|
|
406
469
|
final List<ImportRow> deduped = List.copyOf(unique.values());
|
|
407
470
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
for (ImportRow r : deduped) collections.add(r.collection());
|
|
411
|
-
for (String c : collections) ensureCollectionRegistered(ctx, tenant, c);
|
|
471
|
+
Set<String> collections = new java.util.LinkedHashSet<>();
|
|
472
|
+
for (ImportRow r : deduped) collections.add(r.collection());
|
|
412
473
|
|
|
474
|
+
// Own short committed txns — bounds the first-registration convoy DURATION
|
|
475
|
+
// (see registerCollectionShortTxn doc); also handles markKnown post-commit.
|
|
476
|
+
for (String c : collections) registerCollectionShortTxn(tenant, c);
|
|
477
|
+
int landed = tenantScope.withTenant(tenant, ctx -> {
|
|
413
478
|
var insert = ctx.insertInto(CHASH_INDEX,
|
|
414
479
|
F_TENANT, F_CHASH, F_COLLECTION, F_CREATED_AT);
|
|
415
480
|
for (ImportRow r : deduped) {
|
|
@@ -429,5 +494,6 @@ public final class ChashRepository {
|
|
|
429
494
|
.execute();
|
|
430
495
|
return deduped.size();
|
|
431
496
|
});
|
|
497
|
+
return landed;
|
|
432
498
|
}
|
|
433
499
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (c) 2026 Hal Hildebrand. All rights reserved.
|
|
3
|
+
package dev.nexus.service.db;
|
|
4
|
+
|
|
5
|
+
import java.util.Set;
|
|
6
|
+
import java.util.concurrent.ConcurrentHashMap;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Bead nexus-h8rf6.2 — in-process cache of {@code (tenant, collection)} pairs KNOWN
|
|
10
|
+
* to already have a row in {@code nexus.catalog_collections}.
|
|
11
|
+
*
|
|
12
|
+
* <p><strong>Why this exists.</strong> Both {@code ChashRepository
|
|
13
|
+
* .ensureCollectionRegistered} and {@code PgVectorRepository.upsertChunksInternal}
|
|
14
|
+
* issue {@code INSERT INTO nexus.catalog_collections ... ON CONFLICT (tenant_id,
|
|
15
|
+
* name) DO NOTHING} on EVERY batch write, so the collection stub exists before the
|
|
16
|
+
* chash/chunk row lands. PostgreSQL's {@code ON CONFLICT} clause takes a value lock
|
|
17
|
+
* on the conflicting unique-index entry to safely decide whether to apply DO
|
|
18
|
+
* NOTHING; when two concurrent transactions target the SAME {@code (tenant_id,
|
|
19
|
+
* name)} row — the ordinary case for one repo's indexing run, which writes chash
|
|
20
|
+
* and vector batches for ONE physical collection over and over — the second
|
|
21
|
+
* transaction BLOCKS until the first commits or rolls back, even though the
|
|
22
|
+
* eventual outcome is a no-op. Because the winning transaction typically keeps
|
|
23
|
+
* its connection open for the rest of its own batch (chunk/chash writes), every
|
|
24
|
+
* other concurrent writer to that collection sits blocked HOLDING its own pooled
|
|
25
|
+
* connection for that whole window. Under sustained concurrent indexing this
|
|
26
|
+
* convoy exhausts the shared HikariCP pool: unrelated requests then fail
|
|
27
|
+
* {@code dataSource.getConnection()} with {@code SQLTransientConnectionException}
|
|
28
|
+
* ("Connection is not available, request timed out"), which surfaces as an
|
|
29
|
+
* opaque 500 (reproduced by {@code ChashVectorConcurrencyTest}).
|
|
30
|
+
*
|
|
31
|
+
* <p><strong>Fix shape.</strong> Once a {@code (tenant, collection)} pair is known
|
|
32
|
+
* to be registered, every subsequent write skips the redundant
|
|
33
|
+
* {@code INSERT ... ON CONFLICT} entirely — eliminating the repeated same-row
|
|
34
|
+
* lock-wait for the remainder of the process's lifetime. Only the FIRST
|
|
35
|
+
* registration (racing among whichever concurrent requests reach it first) still
|
|
36
|
+
* pays the lock-wait cost; that window is small and bounded by however many
|
|
37
|
+
* requests happen to race at that exact instant, not by the length of the run.
|
|
38
|
+
*
|
|
39
|
+
* <p><strong>Correctness: mark-known only after commit.</strong> Callers MUST call
|
|
40
|
+
* {@link #markKnown} only after the transaction that performed the (possibly
|
|
41
|
+
* skipped) registration has committed successfully — never from inside the
|
|
42
|
+
* {@code TenantScope.withTenant} lambda itself. If the enclosing transaction later
|
|
43
|
+
* rolls back (e.g. an unrelated error later in the same batch), the
|
|
44
|
+
* {@code catalog_collections} row was never actually persisted; marking the cache
|
|
45
|
+
* eagerly would cause every subsequent writer to skip re-registration forever,
|
|
46
|
+
* silently starving the row. Marking post-commit means a rollback simply leaves
|
|
47
|
+
* the pair unmarked, so the next writer retries registration as usual.
|
|
48
|
+
*
|
|
49
|
+
* <p>Process-local and unbounded by design: {@code (tenant, collection)} pairs are
|
|
50
|
+
* low-cardinality relative to write volume (one entry per physical collection ever
|
|
51
|
+
* touched by this process), so an unbounded {@link ConcurrentHashMap}-backed set is
|
|
52
|
+
* the right trade-off — no eviction complexity, no cache-miss storms.
|
|
53
|
+
*/
|
|
54
|
+
public final class CollectionRegistry {
|
|
55
|
+
|
|
56
|
+
private static final Set<String> KNOWN = ConcurrentHashMap.newKeySet();
|
|
57
|
+
|
|
58
|
+
private CollectionRegistry() {}
|
|
59
|
+
|
|
60
|
+
private static String key(String tenant, String collection) {
|
|
61
|
+
// Printable delimiter on purpose (wave review): the original '\0' made git
|
|
62
|
+
// treat this FILE as binary, so every diff rendered as "Bin N -> M bytes"
|
|
63
|
+
// and logic changes were invisible to text review. '|' is not legal in
|
|
64
|
+
// tenant ids or conformant collection names, so keys cannot collide.
|
|
65
|
+
return tenant + '|' + collection;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** True when {@code (tenant, collection)} is known-registered — safe to skip the INSERT. */
|
|
69
|
+
public static boolean isKnown(String tenant, String collection) {
|
|
70
|
+
return KNOWN.contains(key(tenant, collection));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Record {@code (tenant, collection)} as registered. Callers MUST only invoke
|
|
75
|
+
* this AFTER the enclosing transaction has committed (see class doc).
|
|
76
|
+
*/
|
|
77
|
+
public static void markKnown(String tenant, String collection) {
|
|
78
|
+
KNOWN.add(key(tenant, collection));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Forget {@code (tenant, collection)} — MUST be called after any commit that
|
|
83
|
+
* DELETEs the {@code catalog_collections} row ({@code CatalogRepository
|
|
84
|
+
* .deleteCollection}; the canonical branch of {@code CatalogRepository
|
|
85
|
+
* .renameCollection}, which deletes the OLD row). A stale entry would make
|
|
86
|
+
* every subsequent writer skip re-registration for a later same-named
|
|
87
|
+
* collection, landing chash/chunk rows with no registry stub — the exact
|
|
88
|
+
* silent-skip failure the fail-loud registration design exists to prevent.
|
|
89
|
+
*
|
|
90
|
+
* <p>Same post-commit discipline as {@link #markKnown}: evict only after the
|
|
91
|
+
* deleting transaction has committed. The small window between commit and
|
|
92
|
+
* eviction is fail-loud, not silent — a concurrent writer that skips
|
|
93
|
+
* registration in that window hits the {@code ON DELETE RESTRICT} FK and
|
|
94
|
+
* errors rather than writing orphaned rows.
|
|
95
|
+
*/
|
|
96
|
+
public static void evict(String tenant, String collection) {
|
|
97
|
+
KNOWN.remove(key(tenant, collection));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Test-only: clears all cached entries. */
|
|
101
|
+
static void clearForTests() {
|
|
102
|
+
KNOWN.clear();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -9,7 +9,13 @@ import org.slf4j.LoggerFactory;
|
|
|
9
9
|
import javax.sql.DataSource;
|
|
10
10
|
import java.sql.Connection;
|
|
11
11
|
import java.sql.SQLException;
|
|
12
|
+
import java.sql.SQLTransientConnectionException;
|
|
13
|
+
import java.util.Collections;
|
|
14
|
+
import java.util.IdentityHashMap;
|
|
15
|
+
import java.util.Map;
|
|
12
16
|
import java.util.Set;
|
|
17
|
+
import java.util.concurrent.Semaphore;
|
|
18
|
+
import java.util.concurrent.TimeUnit;
|
|
13
19
|
import java.util.function.Function;
|
|
14
20
|
|
|
15
21
|
/**
|
|
@@ -63,10 +69,61 @@ public final class TenantScope {
|
|
|
63
69
|
*/
|
|
64
70
|
private static final Set<String> PERMITTED_GUCS = Set.of(DEFAULT_TENANT_GUC, T1_TENANT_GUC);
|
|
65
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Per-DataSource admission semaphores (wave review, Java-tree audit High-1).
|
|
74
|
+
*
|
|
75
|
+
* <p>The HTTP layer is virtual-thread-per-request with NO inherent bound on how
|
|
76
|
+
* many requests concurrently attempt DB work against the fixed HikariCP pool.
|
|
77
|
+
* Every convoy fix so far (batched INSERTs, embed-before-borrow,
|
|
78
|
+
* registration-in-own-txn) is per-call-site; this is the SYSTEMIC backpressure:
|
|
79
|
+
* at most {@code 2 * maximumPoolSize} callers may be inside {@link #withTenant}
|
|
80
|
+
* at once (poolSize active + poolSize queued), everyone else gets the same
|
|
81
|
+
* typed retryable pool-exhaustion signal HikariCP's connectionTimeout produces
|
|
82
|
+
* ({@link SQLTransientConnectionException} in the cause chain →
|
|
83
|
+
* {@code HttpUtil.isPoolExhausted} → 503) — without first burning a
|
|
84
|
+
* connectionTimeout wait per surplus caller.
|
|
85
|
+
*
|
|
86
|
+
* <p>Identity-keyed and static because production constructs MULTIPLE
|
|
87
|
+
* TenantScope instances over the SAME DataSource (NexusService + Main's
|
|
88
|
+
* PgVectorRepository) — a per-instance semaphore would multiply the bound.
|
|
89
|
+
* Fair, so a burst cannot starve early arrivals.
|
|
90
|
+
*/
|
|
91
|
+
private static final Map<DataSource, Semaphore> ADMISSION =
|
|
92
|
+
Collections.synchronizedMap(new IdentityHashMap<>());
|
|
93
|
+
|
|
94
|
+
private static final int DEFAULT_POOL_SIZE = 10;
|
|
95
|
+
private static final long DEFAULT_TIMEOUT_MS = 30_000L;
|
|
96
|
+
|
|
66
97
|
private final DataSource dataSource;
|
|
98
|
+
private final Semaphore admission;
|
|
99
|
+
private final long admissionTimeoutMs;
|
|
67
100
|
|
|
68
101
|
public TenantScope(DataSource dataSource) {
|
|
69
102
|
this.dataSource = dataSource;
|
|
103
|
+
int poolSize = DEFAULT_POOL_SIZE;
|
|
104
|
+
long timeoutMs = DEFAULT_TIMEOUT_MS;
|
|
105
|
+
if (dataSource instanceof com.zaxxer.hikari.HikariDataSource hikari) {
|
|
106
|
+
int configured = hikari.getMaximumPoolSize();
|
|
107
|
+
if (configured > 0) {
|
|
108
|
+
poolSize = configured;
|
|
109
|
+
}
|
|
110
|
+
long ct = hikari.getConnectionTimeout();
|
|
111
|
+
if (ct > 0) {
|
|
112
|
+
timeoutMs = ct;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
this.admissionTimeoutMs = timeoutMs;
|
|
116
|
+
final int permits = poolSize * 2;
|
|
117
|
+
this.admission = ADMISSION.computeIfAbsent(
|
|
118
|
+
dataSource, ds -> new Semaphore(permits, true));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Test-only: admission bound + timeout injected directly (stub DataSource path). */
|
|
122
|
+
TenantScope(DataSource dataSource, int admissionPermits, long admissionTimeoutMs) {
|
|
123
|
+
this.dataSource = dataSource;
|
|
124
|
+
this.admissionTimeoutMs = admissionTimeoutMs;
|
|
125
|
+
this.admission = ADMISSION.computeIfAbsent(
|
|
126
|
+
dataSource, ds -> new Semaphore(admissionPermits, true));
|
|
70
127
|
}
|
|
71
128
|
|
|
72
129
|
/**
|
|
@@ -124,6 +181,34 @@ public final class TenantScope {
|
|
|
124
181
|
"gucName not permitted: " + gucName + " (allowed: " + PERMITTED_GUCS + ")");
|
|
125
182
|
}
|
|
126
183
|
|
|
184
|
+
// Admission control (see ADMISSION doc): bound concurrent DB work BEFORE
|
|
185
|
+
// borrowing a connection. Rejection surfaces as the SAME typed retryable
|
|
186
|
+
// signal as HikariCP connectionTimeout (SQLTransientConnectionException in
|
|
187
|
+
// the cause chain), so every handler's sendTypedDbError ladder maps it to
|
|
188
|
+
// a 503 with zero new error-mapping surface.
|
|
189
|
+
boolean admitted;
|
|
190
|
+
try {
|
|
191
|
+
admitted = admission.tryAcquire(admissionTimeoutMs, TimeUnit.MILLISECONDS);
|
|
192
|
+
} catch (InterruptedException ie) {
|
|
193
|
+
Thread.currentThread().interrupt();
|
|
194
|
+
throw new RuntimeException("interrupted awaiting DB admission for tenant: " + tenant, ie);
|
|
195
|
+
}
|
|
196
|
+
if (!admitted) {
|
|
197
|
+
log.warn("event=tenant_scope_admission_timeout tenant={} guc={} timeout_ms={}",
|
|
198
|
+
tenant, gucName, admissionTimeoutMs);
|
|
199
|
+
throw new RuntimeException(
|
|
200
|
+
"DB admission queue full for tenant: " + tenant,
|
|
201
|
+
new SQLTransientConnectionException(
|
|
202
|
+
"admission queue full after " + admissionTimeoutMs + "ms (retryable)"));
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
return stampAndRun(tenant, gucName, work);
|
|
206
|
+
} finally {
|
|
207
|
+
admission.release();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private <T> T stampAndRun(String tenant, String gucName, Function<DSLContext, T> work) {
|
|
127
212
|
Connection conn = null;
|
|
128
213
|
try {
|
|
129
214
|
conn = dataSource.getConnection();
|
|
@@ -125,8 +125,18 @@ public final class TokenCache {
|
|
|
125
125
|
return Optional.empty(); // expired — do not cache
|
|
126
126
|
}
|
|
127
127
|
if (map.size() >= maxEntries) {
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
// Wave review: was map.clear() — evicting EVERY cached principal at once
|
|
129
|
+
// meant the next request from every active tenant paid a synchronous
|
|
130
|
+
// TokenStore round-trip simultaneously (a self-inflicted thundering herd
|
|
131
|
+
// right when the system is busiest). Evict ~25% instead: the flood
|
|
132
|
+
// backstop still bounds memory, but hot tokens survive the trim.
|
|
133
|
+
int toEvict = Math.max(1, maxEntries / 4);
|
|
134
|
+
log.warn("event=token_cache_overflow max={} action=evict count={}", maxEntries, toEvict);
|
|
135
|
+
var it = map.keySet().iterator();
|
|
136
|
+
for (int i = 0; i < toEvict && it.hasNext(); i++) {
|
|
137
|
+
it.next();
|
|
138
|
+
it.remove();
|
|
139
|
+
}
|
|
130
140
|
}
|
|
131
141
|
map.put(tokenHash, new Entry(st.tenantId(), st.isRoot(), st.expiresAt(), now));
|
|
132
142
|
return Optional.of(new Resolved(st.tenantId(), st.isRoot()));
|
{conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/AspectHandler.java
RENAMED
|
@@ -144,28 +144,15 @@ public final class AspectHandler implements HttpHandler {
|
|
|
144
144
|
} catch (IllegalArgumentException e) {
|
|
145
145
|
HttpUtil.send(exchange, 400, "{\"error\":" + HttpUtil.jsonString(e.getMessage()) + "}");
|
|
146
146
|
} catch (Exception e) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// fault. Map it to a typed 409 AHEAD of the generic 500 so the caller sees
|
|
153
|
-
// a loud, actionable failure instead of an opaque 500 (and never a silent
|
|
154
|
-
// 200). jOOQ wraps the driver PSQLException in a DataAccessException, so the
|
|
155
|
-
// violation surfaces as a cause, not the top-level throwable. RF-5 / RF-8.
|
|
156
|
-
// Full driver message (the parameterised SQL + PG detail) goes to the
|
|
157
|
-
// server log for operators; the client body is sanitised to a fixed
|
|
158
|
-
// message + the sqlstate. The 409 is client-triggerable (a bad doc_id),
|
|
159
|
-
// so echoing the raw jOOQ SQL would leak schema/constraint shape to any
|
|
160
|
-
// caller — return only the programmatic signal (sqlstate).
|
|
161
|
-
log.warn("event=aspects_handler_integrity_violation op={} sqlstate={} error={}",
|
|
162
|
-
op, sqlState, e.getMessage());
|
|
163
|
-
HttpUtil.send(exchange, 409,
|
|
164
|
-
"{\"error\":\"integrity constraint violation\",\"sqlstate\":"
|
|
165
|
-
+ HttpUtil.jsonString(sqlState) + "}");
|
|
166
|
-
} else {
|
|
147
|
+
// Shared typed-DB-error ladder: pool-exhaustion 503 + class-23 409
|
|
148
|
+
// (nexus-h8rf6.2 / nexus-7e057) — see HttpUtil.sendTypedDbError.
|
|
149
|
+
// (RDR-172 P3.1 / nexus-gfl3y history preserved on HttpUtil.sendTypedDbError.)
|
|
150
|
+
if (!HttpUtil.sendTypedDbError(exchange, e, log, "aspects_handler",
|
|
151
|
+
"op=" + op)) {
|
|
167
152
|
log.error("event=aspects_handler_error op={} error={}", op, e.getMessage(), e);
|
|
168
|
-
|
|
153
|
+
// Wave review: fixed 500 body — the previous body echoed e.getMessage(),
|
|
154
|
+
// which can carry jOOQ SQL / schema shape to any caller.
|
|
155
|
+
HttpUtil.send(exchange, 500, "{\"error\":\"internal server error\"}");
|
|
169
156
|
}
|
|
170
157
|
}
|
|
171
158
|
}
|
{conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/CatalogHandler.java
RENAMED
|
@@ -199,22 +199,10 @@ public final class CatalogHandler implements HttpHandler {
|
|
|
199
199
|
} catch (IllegalArgumentException e) {
|
|
200
200
|
HttpUtil.send(exchange, 400, "{\"error\":" + MAPPER.writeValueAsString(e.getMessage()) + "}");
|
|
201
201
|
} catch (Exception e) {
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
// integrity violations to a typed 409 ahead of the generic 500. The
|
|
207
|
-
// full driver message goes to the server log; the client body is
|
|
208
|
-
// sanitised to a fixed message + the sqlstate (never the raw jOOQ
|
|
209
|
-
// SQL, which would leak schema/constraint shape to any caller).
|
|
210
|
-
String sqlState = HttpUtil.sqlState23(e);
|
|
211
|
-
if (sqlState != null) {
|
|
212
|
-
log.warn("event=catalog_handler_integrity_violation op={} tenant={} sqlstate={} error={}",
|
|
213
|
-
op, tenant, sqlState, e.getMessage());
|
|
214
|
-
HttpUtil.send(exchange, 409,
|
|
215
|
-
"{\"error\":\"integrity constraint violation\",\"sqlstate\":"
|
|
216
|
-
+ HttpUtil.jsonString(sqlState) + "}");
|
|
217
|
-
} else {
|
|
202
|
+
// Shared typed-DB-error ladder: pool-exhaustion 503 + class-23 409
|
|
203
|
+
// (nexus-h8rf6.2 / nexus-7e057) — see HttpUtil.sendTypedDbError.
|
|
204
|
+
if (!HttpUtil.sendTypedDbError(exchange, e, log, "catalog_handler",
|
|
205
|
+
"op=" + op + " tenant=" + tenant)) {
|
|
218
206
|
log.error("event=catalog_handler_error op={} tenant={} error={}", op, tenant, e.getMessage(), e);
|
|
219
207
|
HttpUtil.send(exchange, 500, "{\"error\":\"internal server error\"}");
|
|
220
208
|
}
|
{conexus-6.2.0 → conexus-6.3.0}/service/src/main/java/dev/nexus/service/http/ChashHandler.java
RENAMED
|
@@ -91,8 +91,13 @@ public final class ChashHandler implements HttpHandler {
|
|
|
91
91
|
} catch (IllegalArgumentException e) {
|
|
92
92
|
HttpUtil.send(exchange, 400, "{\"error\":" + MAPPER.writeValueAsString(e.getMessage()) + "}");
|
|
93
93
|
} catch (Exception e) {
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
// Shared typed-DB-error ladder: pool-exhaustion 503 + class-23 409
|
|
95
|
+
// (nexus-h8rf6.2 / nexus-7e057) — see HttpUtil.sendTypedDbError.
|
|
96
|
+
if (!HttpUtil.sendTypedDbError(exchange, e, log, "chash_handler",
|
|
97
|
+
"op=" + op + " tenant=" + tenant)) {
|
|
98
|
+
log.error("event=chash_handler_error op={} tenant={} error={}", op, tenant, e.getMessage(), e);
|
|
99
|
+
HttpUtil.send(exchange, 500, "{\"error\":\"internal server error\"}");
|
|
100
|
+
}
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
|