docs: make schema v3 the only workspace contract
This commit is contained in:
@@ -214,7 +214,7 @@ cat >"$project_state_positive" <<'EOF'
|
||||
|
||||
## Internal Qdrant + Ollama semantic infrastructure — LIVE 2026-08-08
|
||||
|
||||
- Schema-v3 descriptors are operational and v1/v2 remain `migration_required`.
|
||||
- Schema v3 is the only accepted workspace descriptor format. Schema v1 and v2 descriptors are rejected before activation or diagnostics.
|
||||
- One workspace owns one Qdrant collection.
|
||||
- Only DWH and LLM remain external runtime application endpoints.
|
||||
- The internal stack includes `qdrant`, `embedding`, and `embedding-model-init`.
|
||||
@@ -223,10 +223,146 @@ cat >"$project_state_positive" <<'EOF'
|
||||
|
||||
### Historical snapshot — previous deployment
|
||||
|
||||
- Older notes intentionally live only here.
|
||||
- Schema-v2 descriptors were operational and returned `migration_required`.
|
||||
- Operators used `migrate-legacy` in this superseded workflow.
|
||||
EOF
|
||||
verify_project_state_current_contract "$project_state_positive" positive-project-state >/dev/null
|
||||
|
||||
project_state_unrelated_migration="$negative_root/project-state-unrelated-migration.md"
|
||||
python3 - "$project_state_positive" "$project_state_unrelated_migration" <<'PY'
|
||||
import pathlib, sys
|
||||
source = pathlib.Path(sys.argv[1]).read_text()
|
||||
old = "rejected before activation or diagnostics.\n- One workspace"
|
||||
new = (
|
||||
"rejected before activation or diagnostics. The unrelated session database\n"
|
||||
" upgrade may report `migration_required`.\n- One workspace"
|
||||
)
|
||||
if source.count(old) != 1:
|
||||
raise SystemExit("PROJECT_STATE positive fixture insertion point not found")
|
||||
pathlib.Path(sys.argv[2]).write_text(source.replace(old, new, 1))
|
||||
PY
|
||||
verify_project_state_current_contract "$project_state_unrelated_migration" \
|
||||
unrelated-current-project-state >/dev/null
|
||||
|
||||
generic_unrelated_migration="$negative_root/generic-unrelated-migration.md"
|
||||
python3 - "$root/docs/install/local-workspace-registry.md" "$generic_unrelated_migration" <<'PY'
|
||||
import pathlib, sys
|
||||
source = pathlib.Path(sys.argv[1]).read_text()
|
||||
old = "isolated by payload `kind`.\n\n## Semantic index ownership contract"
|
||||
new = (
|
||||
"isolated by payload `kind`. The unrelated session database\n"
|
||||
"upgrade may report `migration_required`.\n\n## Semantic index ownership contract"
|
||||
)
|
||||
if source.count(old) != 1:
|
||||
raise SystemExit("manual positive fixture insertion point not found")
|
||||
pathlib.Path(sys.argv[2]).write_text(source.replace(old, new, 1))
|
||||
PY
|
||||
verify_workspace_descriptor_doc_contract "$generic_unrelated_migration" \
|
||||
unrelated-current-manual >/dev/null
|
||||
|
||||
assert_schema_contract_rejected() {
|
||||
local source="$1" label="$2" expected="$3" output="$negative_root/schema-contract-output"
|
||||
set +e
|
||||
verify_workspace_descriptor_doc_contract "$source" "$label" >"$output" 2>&1
|
||||
local status=$?
|
||||
set -e
|
||||
if [[ $status -eq 0 ]] || ! grep -Fq "$expected" "$output"; then
|
||||
echo "$label fixture was not rejected correctly" >&2
|
||||
cat "$output" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
project_state_migration_required="$negative_root/project-state-migration-required.md"
|
||||
python3 - "$project_state_positive" "$project_state_migration_required" <<'PY'
|
||||
import pathlib, sys
|
||||
source = pathlib.Path(sys.argv[1]).read_text()
|
||||
marker = source.index("## Historical snapshots")
|
||||
pathlib.Path(sys.argv[2]).write_text(
|
||||
source[:marker]
|
||||
+ "- Schema v1 and v2 descriptors remain\n"
|
||||
+ " `migration_required`.\n\n"
|
||||
+ source[marker:]
|
||||
)
|
||||
PY
|
||||
set +e
|
||||
verify_project_state_current_contract "$project_state_migration_required" current-migration-required >"$project_state_output" 2>&1
|
||||
project_state_status=$?
|
||||
set -e
|
||||
if [[ $project_state_status -eq 0 ]] || ! grep -Fq "migration_required" "$project_state_output"; then
|
||||
echo "current PROJECT_STATE migration_required fixture was not rejected correctly" >&2
|
||||
cat "$project_state_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
project_state_readable="$negative_root/project-state-readable.md"
|
||||
python3 - "$project_state_positive" "$project_state_readable" <<'PY'
|
||||
import pathlib, sys
|
||||
source = pathlib.Path(sys.argv[1]).read_text()
|
||||
source = source.replace(
|
||||
"Schema v1 and v2 descriptors are rejected before activation or diagnostics.",
|
||||
"Schema v1 and v2 descriptors remain readable for operational use.",
|
||||
1,
|
||||
)
|
||||
pathlib.Path(sys.argv[2]).write_text(source)
|
||||
PY
|
||||
set +e
|
||||
verify_project_state_current_contract "$project_state_readable" current-readable-v1-v2 >"$project_state_output" 2>&1
|
||||
project_state_status=$?
|
||||
set -e
|
||||
if [[ $project_state_status -eq 0 ]] || ! grep -Eq "rejected|readable|operational" "$project_state_output"; then
|
||||
echo "current PROJECT_STATE v1/v2 readability fixture was not rejected correctly" >&2
|
||||
cat "$project_state_output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
manual_migration_required="$negative_root/manual-migration-required.md"
|
||||
cp "$root/docs/install/local-workspace-registry.md" "$manual_migration_required"
|
||||
printf '\nSchema v1 and v2 descriptors remain\n`migration_required`.\n' \
|
||||
>>"$manual_migration_required"
|
||||
assert_schema_contract_rejected "$manual_migration_required" manual-migration-required "migration_required"
|
||||
|
||||
manual_migrate_legacy="$negative_root/manual-migrate-legacy.md"
|
||||
cp "$root/docs/install/local-workspace-registry.md" "$manual_migrate_legacy"
|
||||
printf '\nRun `node backend/dist/workspaces/migrate-legacy.js` before activation.\n' >>"$manual_migrate_legacy"
|
||||
assert_schema_contract_rejected "$manual_migrate_legacy" manual-migrate-legacy "migrate-legacy"
|
||||
|
||||
manual_legacy_procedure="$negative_root/manual-legacy-procedure.md"
|
||||
cp "$root/docs/install/server-workspace-registry.md" "$manual_legacy_procedure"
|
||||
printf '\nMigrate legacy descriptors in a temporary review clone before activation.\n' >>"$manual_legacy_procedure"
|
||||
assert_schema_contract_rejected "$manual_legacy_procedure" manual-legacy-procedure "legacy descriptor procedure"
|
||||
|
||||
manual_missing_v3_only="$negative_root/manual-missing-v3-only.md"
|
||||
python3 - "$root/docs/install/local-workspace-registry.md" "$manual_missing_v3_only" <<'PY'
|
||||
import pathlib, re, sys
|
||||
text = pathlib.Path(sys.argv[1]).read_text()
|
||||
text = re.sub(
|
||||
r"Schema v3 is the only accepted workspace descriptor format\.",
|
||||
"Schema v3 is accepted as a workspace descriptor format.",
|
||||
text,
|
||||
count=1,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
pathlib.Path(sys.argv[2]).write_text(text)
|
||||
PY
|
||||
assert_schema_contract_rejected "$manual_missing_v3_only" manual-missing-v3-only "v3-only acceptance"
|
||||
|
||||
diagnostics_readable="$negative_root/diagnostics-readable-v1-v2.md"
|
||||
python3 - "$root/docs/workspace-diagnostic-protocol.md" "$diagnostics_readable" <<'PY'
|
||||
import pathlib, re, sys
|
||||
text = pathlib.Path(sys.argv[1]).read_text()
|
||||
text, count = re.subn(
|
||||
r"Schema v1 and v2 descriptors are\s+rejected before diagnostics run\.",
|
||||
"Schema v1 and v2 descriptors remain readable for operational diagnostics.",
|
||||
text,
|
||||
count=1,
|
||||
)
|
||||
if count != 1:
|
||||
raise SystemExit("diagnostic rejection sentence not found")
|
||||
pathlib.Path(sys.argv[2]).write_text(text)
|
||||
PY
|
||||
assert_schema_contract_rejected "$diagnostics_readable" diagnostics-readable-v1-v2 "v1/v2 rejection"
|
||||
|
||||
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'
|
||||
|
||||
Reference in New Issue
Block a user