docs: relax semantic doc assertions

This commit is contained in:
2026-08-08 21:08:07 +02:00
parent aa502dcf7d
commit b84d4db946
4 changed files with 179 additions and 25 deletions
@@ -91,3 +91,33 @@ Observed RED before the fix:
```text ```text
PROJECT_STATE.md: missing Historical snapshots boundary 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)
```
+9 -9
View File
@@ -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`. - **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`. - 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`. - 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 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` 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. (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 - **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 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`; Running image ids: core `sha256:55acef2f12151ea97144c2f5e9164d63f2ca734bc2746fef553df94849e3fb3f`;
frontend `sha256:1043f79392420149655cc63d70461e2ca2005b2290a1e3e21dcf845ec3bd1c81`. 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 - **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 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 ID and running container image ID both equal
`sha256:577f99754fd0731251c8ddd8608b1b8baee09d02fad66c759b23f8221083e676`. `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`, - **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 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 exited 0 with `controller.abort()` in cleanup, preserving the gate, session cleanup, and exact
settings-restoration evidence. 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 - **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, 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 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. 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, - **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 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, 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. 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 - **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, 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 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. 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 - **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, 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 sensitive/error pattern scan was **0**. No live model smoke was run; settings and sessions were
intentionally untouched. 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 - **Source and verification (`2026-07-15T15:56:57+02:00`).** Deployed source commit
`1f540fcb78ac9e552e56a21e47edf66e9872b323` (`1f540fc`). Frontend Vitest passed **298/298** `1f540fcb78ac9e552e56a21e47edf66e9872b323` (`1f540fc`). Frontend Vitest passed **298/298**
@@ -159,6 +159,26 @@ if [[ $project_state_status -eq 0 ]] || ! grep -Fq "contradictory active text" "
exit 1 exit 1
fi 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" workspace_fixture="$negative_root/workspace-invalid.yaml"
python3 - "$root/deploy/workspaces/example.yaml" "$workspace_fixture" <<'PY' python3 - "$root/deploy/workspaces/example.yaml" "$workspace_fixture" <<'PY'
import pathlib, sys, yaml import pathlib, sys, yaml
@@ -198,6 +218,87 @@ cat >"$project_state_positive" <<'EOF'
EOF EOF
verify_project_state_current_contract "$project_state_positive" positive-project-state >/dev/null 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_reorder="$negative_root/caddy-adapted-reorder.json"
adapted_bypass="$negative_root/caddy-adapted-bypass.json" adapted_bypass="$negative_root/caddy-adapted-bypass.json"
node - "$adapted_reorder" "$adapted_bypass" <<'NODE' node - "$adapted_reorder" "$adapted_bypass" <<'NODE'
+39 -16
View File
@@ -91,6 +91,20 @@ require_text() {
done 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() { verify_compose_internal_semantic_contract() {
python3 - "$root/compose.yaml" <<'PY' python3 - "$root/compose.yaml" <<'PY'
import sys, yaml, pathlib import sys, yaml, pathlib
@@ -193,17 +207,20 @@ if not marker:
raise SystemExit(f"{label}: missing Historical snapshots boundary") raise SystemExit(f"{label}: missing Historical snapshots boundary")
current = text[:marker.start()] current = text[:marker.start()]
historical = text[marker.start():] historical = text[marker.start():]
required = [ if not re.search(r"Internal Qdrant \+ Ollama semantic infrastructure", current, re.MULTILINE):
r"Internal Qdrant \+ Ollama semantic infrastructure", raise SystemExit(f"{label}: current section missing internal semantic snapshot heading")
r"Schema-v3 descriptors are operational", if not re.search(r"Schema-v3 descriptors are operational", current, re.MULTILINE):
r"migration_required", raise SystemExit(f"{label}: current section must say schema-v3 is operational")
r"One workspace owns one Qdrant collection", if "migration_required" not in current:
r"Only DWH and LLM remain external", raise SystemExit(f"{label}: current section must mention migration_required")
r"embedding-model-init", 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")
for pattern in required: if not re.search(r"\bDWH\b", current) or not re.search(r"\bLLM\b", current):
if not re.search(pattern, current, re.MULTILINE): raise SystemExit(f"{label}: current section must identify DWH and LLM")
raise SystemExit(f"{label}: current section missing {pattern}") 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 = [ forbidden = [
r"Schema-v2 descriptors are operational", r"Schema-v2 descriptors are operational",
r"supported Compose stack is exactly `frontend` plus `core`", r"supported Compose stack is exactly `frontend` plus `core`",
@@ -213,8 +230,8 @@ forbidden = [
for pattern in forbidden: for pattern in forbidden:
if re.search(pattern, current, re.MULTILINE): if re.search(pattern, current, re.MULTILINE):
raise SystemExit(f"{label}: current section still contains contradictory active text: {pattern}") raise SystemExit(f"{label}: current section still contains contradictory active text: {pattern}")
if re.search(r"^## .*— LIVE", historical, re.MULTILINE): 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 LIVE headings") raise SystemExit(f"{label}: historical section still contains active/live heading markers")
PY PY
} }
@@ -243,13 +260,19 @@ verify_internal_semantic_infrastructure_docs() {
for manual in "$local_manual" "$server_manual"; do for manual in "$local_manual" "$server_manual"; do
require_pattern "$manual" "$(basename "$manual")" 'qwen3-embedding:0\.6b' || return 1 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")" '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 done
require_pattern "$local_manual" "local workspace manual" 'CPU-first' || return 1 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 "$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" '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 "$server_manual" "server workspace manual" '(Git remote|DWH|LLM|bastion)' || 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" '(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 "$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" 'schema version 3' || return 1
require_pattern "$diagnostics" "workspace diagnostic protocol" 'semantic_index_incompatible' || return 1 require_pattern "$diagnostics" "workspace diagnostic protocol" 'semantic_index_incompatible' || return 1