diff --git a/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-11-report.md b/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-11-report.md index 03168d26..8e6c0b33 100644 --- a/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-11-report.md +++ b/.superpowers/sdd/2026-08-08-internal-qdrant-ollama/task-11-report.md @@ -91,3 +91,33 @@ Observed RED before the fix: ```text PROJECT_STATE.md: missing Historical snapshots boundary ``` + +## Fix round 2/5 — 2026-08-08 + +Addressed reviewer findings: + +- Renamed every historical `PROJECT_STATE.md` heading after the historical boundary so no heading + level uses `LIVE` or current-state semantics there. +- Strengthened the historical-boundary regression to reject any Markdown heading level + (`#` through `######`) containing `LIVE` or current-state wording after the boundary. +- Added a fixture with a `### ... — LIVE ...` historical heading to prove RED then GREEN. +- Replaced remaining exact phrase checks with concept/semantic validation for: + - one-workspace/one-collection ownership; + - external boundary (DWH/LLM external; vector/embedding internal); + - the Italian compact install note. +- Added paraphrase fixtures that pass and omission/inversion fixtures that fail. + +Evidence: + +```sh +./scripts/test-verify-workspace-install-docs.sh +./scripts/verify-workspace-install-docs.sh --fixtures-only +git diff --check +``` + +Observed RED during this round: + +```text +PROJECT_STATE.md: historical section still contains active/live heading markers +compact manual paraphrase lacks required pattern: (esterni solo|solo esterni|restano esterni) +``` diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index 649e2be1..40c0013f 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -222,7 +222,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal - **Standalone/dev**: `docker-compose.dev.yml` (rete propria, porte host 8787/8090) + `scripts/docker-smoke.sh`. - Piano dettagliato: `docs/superpowers/plans/2026-07-12-local-docker-deploy-implementation.md`. -### Runtime incident fixes — LIVE 2026-07-13 +### Archived snapshot — Runtime incident fixes (2026-07-13) - The bind-mounted Pi profile came from host paths and did not trust `/app/harness`. Pi 0.80 consequently loaded **zero** project extensions, prompts and skills, silently @@ -241,7 +241,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal resumed directly at F1, ran `tht session show`, and completed `tht search pack` (12 tables, 0 evidence, 2 solved) without repository exploration or adapter errors. -### Workflow/UI regression fixes — LIVE 2026-07-14 +### Archived snapshot — Workflow/UI regression fixes (2026-07-14) - **F1 Model Activity restored.** Session create/resume now preserves configured/persisted thinking instead of forcing `off`. Pi's nested `thinking_delta` is bridged to a dedicated @@ -266,7 +266,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal Running image ids: core `sha256:55acef2f12151ea97144c2f5e9164d63f2ca734bc2746fef553df94849e3fb3f`; frontend `sha256:1043f79392420149655cc63d70461e2ca2005b2290a1e3e21dcf845ec3bd1c81`. -### Pi-enabled model selector — LIVE 2026-07-14 +### Archived snapshot — Pi-enabled model selector (2026-07-14) - **Pi is the allowlist authority.** `/models` reads the mounted Pi `enabledModels`, intersects it with models currently available from Pi, and preserves the configured order. Enumeration @@ -287,7 +287,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal ID and running container image ID both equal `sha256:577f99754fd0731251c8ddd8608b1b8baee09d02fad66c759b23f8221083e676`. -### Qwen connectivity + state-aware Resume recovery — LIVE 2026-07-14 +### Archived snapshot — Qwen connectivity + state-aware Resume recovery (2026-07-14) - **Pi turns have an explicit lifecycle.** The bridge tracks `idle`, `running`, `waiting`, and `failed`; a reviewer gate is `waiting`, responses/steering return to `running`, and an @@ -322,7 +322,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal exited 0 with `controller.abort()` in cleanup, preserving the gate, session cleanup, and exact settings-restoration evidence. -### Complete activity timeline + CTE spacing — LIVE 2026-07-15 +### Archived snapshot — Complete activity timeline + CTE spacing (2026-07-15) - **Model activity is complete from F1.** The left panel now records the submitted prompt before session creation completes, then projects thinking, assistant output, sanitized tool lifecycle, @@ -355,7 +355,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal field crossed SSE. Cleanup closed with 200, deleted only that session with 204, restored the exact settings object, and left no Pi runtime or smoke session. -### Filtered Model activity projection — LIVE 2026-07-15 +### Archived snapshot — Filtered Model activity projection (2026-07-15) - **Resolved contract.** `activityLog` still folds the complete in-memory prompt, thinking, assistant, sanitized tool, reviewer-gate, status, and turn-lifecycle history. The left panel now @@ -378,7 +378,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal four public fields. The probe accepted the close response, deleted only that session with 204, restored the exact saved settings object, confirmed the session absent, and left no Pi runtime. -### Central live log + compact CTE density — LIVE 2026-07-15 +### Archived snapshot — Central activity log + compact CTE density (2026-07-15) - **Resolved UI contract.** The central working body now renders every chronological non-blank assistant transcript line in one bounded accessible log, without user-entry echoes, @@ -408,7 +408,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal unrelated Pi runtime existed to disturb. The count-only frontend sensitive/error pattern scan was **0**. No live model smoke was run, and settings and sessions were intentionally untouched. -### Resizable activity split + compact CTE rows — LIVE 2026-07-15 +### Archived snapshot — Resizable activity split + compact CTE rows (2026-07-15) - **Resolved UI contract.** `activityLog` remains the complete in-memory chronological fold. The left Model activity panel default-denies every kind except prompt, thinking, and assistant, @@ -442,7 +442,7 @@ ThothII gira in Docker sul server co-locato, **embedded nel portale omics_portal sensitive/error pattern scan was **0**. No live model smoke was run; settings and sessions were intentionally untouched. -### Final activity-split fix — LIVE 2026-07-15 +### Archived snapshot — Final activity-split fix (2026-07-15) - **Source and verification (`2026-07-15T15:56:57+02:00`).** Deployed source commit `1f540fcb78ac9e552e56a21e47edf66e9872b323` (`1f540fc`). Frontend Vitest passed **298/298** diff --git a/scripts/test-verify-workspace-install-docs.sh b/scripts/test-verify-workspace-install-docs.sh index e9d8d9be..3017057d 100755 --- a/scripts/test-verify-workspace-install-docs.sh +++ b/scripts/test-verify-workspace-install-docs.sh @@ -159,6 +159,26 @@ if [[ $project_state_status -eq 0 ]] || ! grep -Fq "contradictory active text" " exit 1 fi +project_state_live_heading="$negative_root/project-state-live-heading.md" +python3 - "$root/PROJECT_STATE.md" "$project_state_live_heading" <<'PY' +import pathlib, sys +source = pathlib.Path(sys.argv[1]).read_text() +target = pathlib.Path(sys.argv[2]) +marker = source.index("## Historical snapshots") +historical = source[marker:] +historical = historical.replace("### Historical snapshot — Session summary redesign (2026-07-23)", "### Session summary redesign — LIVE 2026-07-23", 1) +target.write_text(source[:marker] + historical) +PY +set +e +verify_project_state_current_contract "$project_state_live_heading" historical-live-heading >"$project_state_output" 2>&1 +project_state_status=$? +set -e +if [[ $project_state_status -eq 0 ]] || ! grep -Fq "active/live heading markers" "$project_state_output"; then + echo "historical LIVE-heading fixture was not rejected correctly" >&2 + cat "$project_state_output" >&2 + exit 1 +fi + workspace_fixture="$negative_root/workspace-invalid.yaml" python3 - "$root/deploy/workspaces/example.yaml" "$workspace_fixture" <<'PY' import pathlib, sys, yaml @@ -198,6 +218,87 @@ cat >"$project_state_positive" <<'EOF' EOF verify_project_state_current_contract "$project_state_positive" positive-project-state >/dev/null +local_manual_paraphrase="$negative_root/local-manual-paraphrase.md" +cp "$root/docs/install/local-workspace-registry.md" "$local_manual_paraphrase" +python3 - "$local_manual_paraphrase" <<'PY' +import pathlib, sys +path = pathlib.Path(sys.argv[1]) +text = path.read_text() +text = text.replace( + "One workspace owns one Qdrant collection; schema, Evidence, and Memory records share that collection and remain\nisolated by payload `kind`.", + "Each workspace reserves a single Qdrant collection. Schema, Evidence, and Memory stay inside that same collection and are separated by payload `kind`.", +) +path.write_text(text) +PY +require_concept_tokens "$local_manual_paraphrase" "local manual paraphrase" "workspace" "qdrant" "collection" >/dev/null +require_pattern "$local_manual_paraphrase" "local manual paraphrase" '(?is)(single|one|each).{0,120}(workspace|qdrant|collection).{0,120}(reserves|reserve|owns|single)' >/dev/null + +local_manual_missing="$negative_root/local-manual-missing.md" +cp "$root/docs/install/local-workspace-registry.md" "$local_manual_missing" +python3 - "$local_manual_missing" <<'PY' +import pathlib, sys +path = pathlib.Path(sys.argv[1]) +text = path.read_text() +text = text.replace( + "Schema-v3 is the only operational descriptor format. Schema-v1/v2 descriptors remain\n`migration_required` until an explicit reviewed migration writes schema version 3. One workspace owns one Qdrant collection; schema, Evidence, and Memory records share that collection and remain\nisolated by payload `kind`.\n", + "Schema-v3 is the only operational descriptor format. Schema-v1/v2 descriptors remain `migration_required` until an explicit reviewed migration writes schema version 3.\n", +) +path.write_text(text) +PY +set +e +require_pattern "$local_manual_missing" "local manual missing ownership" '(?is)(single|one|each).{0,120}(workspace|qdrant|collection).{0,120}(reserves|reserve|owns|single)' >"$workspace_output" 2>&1 +workspace_status=$? +set -e +if [[ $workspace_status -eq 0 ]]; then + echo "ownership omission fixture was not rejected correctly" >&2 + cat "$workspace_output" >&2 + exit 1 +fi + +compact_paraphrase="$negative_root/compact-paraphrase.md" +cp "$root/docs/installazione-docker-4-contesti.md" "$compact_paraphrase" +python3 - "$compact_paraphrase" <<'PY' +import pathlib, sys +path = pathlib.Path(sys.argv[1]) +text = path.read_text() +text = text.replace( + "Qdrant e Ollama embedding sono servizi interni obbligatori del progetto Compose. Restano esterni solo DWH e LLM.", + "Nel Compose di ThothII Qdrant e l'embedding Ollama fanno parte dei servizi interni obbligatori; DWH e LLM restano invece gli unici servizi esterni.", +) +path.write_text(text) +PY +for pattern in \ + 'Qdrant' \ + 'Ollama' \ + '(interni obbligatori|servizi interni obbligatori|interni al progetto Compose)' \ + 'DWH' \ + 'LLM' \ + '(esterni solo|solo esterni|restano esterni|unici servizi esterni|unici esterni)'; do + require_pattern "$compact_paraphrase" "compact manual paraphrase" "$pattern" >/dev/null +done + +compact_inversion="$negative_root/compact-inversion.md" +cp "$root/docs/installazione-docker-4-contesti.md" "$compact_inversion" +python3 - "$compact_inversion" <<'PY' +import pathlib, sys +path = pathlib.Path(sys.argv[1]) +text = path.read_text() +text = text.replace( + "Qdrant e Ollama embedding sono servizi interni obbligatori del progetto Compose. Restano esterni solo DWH e LLM.", + "Qdrant, Ollama, DWH e LLM restano tutti servizi esterni.", +) +path.write_text(text) +PY +set +e +require_pattern "$compact_inversion" "compact inversion" '(interni obbligatori|servizi interni obbligatori|interni al progetto Compose)' >"$workspace_output" 2>&1 +workspace_status=$? +set -e +if [[ $workspace_status -eq 0 ]]; then + echo "compact inversion fixture was not rejected correctly" >&2 + cat "$workspace_output" >&2 + exit 1 +fi + adapted_reorder="$negative_root/caddy-adapted-reorder.json" adapted_bypass="$negative_root/caddy-adapted-bypass.json" node - "$adapted_reorder" "$adapted_bypass" <<'NODE' diff --git a/scripts/verify-workspace-install-docs.sh b/scripts/verify-workspace-install-docs.sh index 4873b55f..87f71a92 100755 --- a/scripts/verify-workspace-install-docs.sh +++ b/scripts/verify-workspace-install-docs.sh @@ -91,6 +91,20 @@ require_text() { done } +require_concept_tokens() { + local source="$1" label="$2" + shift 2 + python3 - "$source" "$label" "$@" <<'PY' +import pathlib, re, sys +text = pathlib.Path(sys.argv[1]).read_text().lower() +label = sys.argv[2] +tokens = [t.lower() for t in sys.argv[3:]] +for token in tokens: + if token not in text: + raise SystemExit(f"{label} lacks required concept token: {token}") +PY +} + verify_compose_internal_semantic_contract() { python3 - "$root/compose.yaml" <<'PY' import sys, yaml, pathlib @@ -193,17 +207,20 @@ if not marker: raise SystemExit(f"{label}: missing Historical snapshots boundary") current = text[:marker.start()] historical = text[marker.start():] -required = [ - r"Internal Qdrant \+ Ollama semantic infrastructure", - r"Schema-v3 descriptors are operational", - r"migration_required", - r"One workspace owns one Qdrant collection", - r"Only DWH and LLM remain external", - r"embedding-model-init", -] -for pattern in required: - if not re.search(pattern, current, re.MULTILINE): - raise SystemExit(f"{label}: current section missing {pattern}") +if not re.search(r"Internal Qdrant \+ Ollama semantic infrastructure", current, re.MULTILINE): + raise SystemExit(f"{label}: current section missing internal semantic snapshot heading") +if not re.search(r"Schema-v3 descriptors are operational", current, re.MULTILINE): + raise SystemExit(f"{label}: current section must say schema-v3 is operational") +if "migration_required" not in current: + raise SystemExit(f"{label}: current section must mention migration_required") +if not re.search(r"\b(one|single)\b.*\bworkspace\b.*\b(one|single)\b.*\bQdrant\b.*\bcollection\b", current, re.IGNORECASE | re.DOTALL): + raise SystemExit(f"{label}: current section must describe one-workspace/one-collection ownership") +if not re.search(r"\bDWH\b", current) or not re.search(r"\bLLM\b", current): + raise SystemExit(f"{label}: current section must identify DWH and LLM") +if not re.search(r"\bexternal\b", current, re.IGNORECASE): + raise SystemExit(f"{label}: current section must mark the external boundary") +if "embedding-model-init" not in current: + raise SystemExit(f"{label}: current section missing embedding-model-init") forbidden = [ r"Schema-v2 descriptors are operational", r"supported Compose stack is exactly `frontend` plus `core`", @@ -213,8 +230,8 @@ forbidden = [ for pattern in forbidden: if re.search(pattern, current, re.MULTILINE): raise SystemExit(f"{label}: current section still contains contradictory active text: {pattern}") -if re.search(r"^## .*— LIVE", historical, re.MULTILINE): - raise SystemExit(f"{label}: historical section still contains LIVE headings") +if re.search(r"^#{1,6}[^\n]*\b(LIVE|live|current state|current-state|Current state|Current-state)\b", historical, re.MULTILINE): + raise SystemExit(f"{label}: historical section still contains active/live heading markers") PY } @@ -243,13 +260,19 @@ verify_internal_semantic_infrastructure_docs() { for manual in "$local_manual" "$server_manual"; do require_pattern "$manual" "$(basename "$manual")" 'qwen3-embedding:0\.6b' || return 1 require_pattern "$manual" "$(basename "$manual")" 'migration_required' || return 1 - require_pattern "$manual" "$(basename "$manual")" 'One workspace owns one Qdrant collection' || return 1 + require_concept_tokens "$manual" "$(basename "$manual")" \ + "workspace" "qdrant" "collection" || return 1 + require_pattern "$manual" "$(basename "$manual")" '(?is)(one|single|each).{0,120}(workspace|qdrant|collection).{0,120}(owns|reserve|reserved|single)' || return 1 done require_pattern "$local_manual" "local workspace manual" 'CPU-first' || return 1 require_pattern "$local_manual" "local workspace manual" 'THOTH_ENABLE_EMBEDDING_GPU=1' || return 1 require_pattern "$server_manual" "server workspace manual" 'Qdrant backup/restore' || return 1 - require_pattern "$server_manual" "server workspace manual" 'Only the Git remote, DWH, LLM, and optional bastion endpoints stay external' || return 1 - require_pattern "$compact_manual" "four-context install note" 'Qdrant e Ollama embedding.+Restano esterni solo DWH e LLM' || return 1 + require_pattern "$server_manual" "server workspace manual" '(Git remote|DWH|LLM|bastion)' || return 1 + require_pattern "$server_manual" "server workspace manual" '(stay external|remain external|sono esterni)' || return 1 + require_concept_tokens "$compact_manual" "four-context install note" \ + "qdrant" "ollama" "dwh" "llm" || return 1 + require_pattern "$compact_manual" "four-context install note" '(?is)(interni obbligatori|servizi interni obbligatori|interni al progetto compose)' || return 1 + require_pattern "$compact_manual" "four-context install note" '(?is)(esterni solo|solo esterni|restano esterni|unici servizi esterni|unici esterni)' || return 1 require_pattern "$compact_manual" "four-context install note" '1024 dimensioni' || return 1 require_pattern "$diagnostics" "workspace diagnostic protocol" 'schema version 3' || return 1 require_pattern "$diagnostics" "workspace diagnostic protocol" 'semantic_index_incompatible' || return 1