feat: P4 qdrant collection lifecycle (self-heal + guarded rebuild)

- shared TS collection manager: self-heal creates missing collection (1024/cosine)
  and missing keyword payload indexes; never mutates incompatible contracts
  (semantic_index_incompatible); async index visibility polled with bounded deadline
- session admission (qdrantEnsure) uses the manager in self-heal mode; operator path
  keeps require_existing semantics
- runtime lease exposes semanticQdrantUrl to the operator
- operator commands vector-inspect/vector-rebuild with exact confirmation guards
- thothctl workspace vector inspect|rebuild (Go) with --collection/--confirm/--destroy
- p4 acceptance runner: real Qdrant (v1.18.2) lifecycle checks, 11/11 PASS
- docs: CLI contract, manual walkthrough P4 (PENDING), PROJECT_STATE
This commit is contained in:
2026-08-12 20:00:14 +02:00
parent 230a876314
commit e056c19e62
20 changed files with 1041 additions and 32 deletions
@@ -57,6 +57,7 @@ export interface RenderedWorkspaceRuntime {
bindings: RuntimeBindings;
bindingDigest: string;
renderedConfig: string;
semanticQdrantUrl: string;
}
export interface ActiveRenderedWorkspaceRuntime extends RenderedWorkspaceRuntime {
@@ -71,6 +72,7 @@ export interface DeterministicRuntimeConfigLease extends RuntimeConfigLease {
catalogBlob: string;
configDigest: string;
bindingDigest: string;
semanticQdrantUrl: string;
effectiveConfig: CanonicalEffectiveConfig;
effectiveConfigIdentity: string;
configFingerprint: string;
@@ -310,6 +312,7 @@ function renderWorkspaceRuntimeFromWorkspace(options: {
installationOverlay: overlay,
bindings,
bindingDigest: stableBindingDigest(bindings),
semanticQdrantUrl: options.semanticRuntime.internalQdrantUrl,
renderedConfig: renderRuntimeConfig(
options.workspace,
bindings,
@@ -508,6 +511,7 @@ export async function publishDeterministicRuntimeConfigLease(options: {
catalogBlob: rendered.catalogBlob,
configDigest,
bindingDigest: rendered.bindingDigest,
semanticQdrantUrl: rendered.semanticQdrantUrl,
effectiveConfig,
effectiveConfigIdentity: effectiveConfigIdentityValue,
configFingerprint: configFingerprintValue,
@@ -570,6 +574,7 @@ export async function publishDeterministicRuntimeConfigLease(options: {
catalogBlob: rendered.catalogBlob,
configDigest,
bindingDigest: rendered.bindingDigest,
semanticQdrantUrl: rendered.semanticQdrantUrl,
effectiveConfig,
effectiveConfigIdentity: effectiveConfigIdentityValue,
configFingerprint: configFingerprintValue,