From 6e05b3179439e5eaa6a1cae1f18bce16be8e7a31 Mon Sep 17 00:00:00 2001 From: kl3inIT Date: Wed, 29 Jul 2026 22:18:14 +0700 Subject: [PATCH] fix: make docs deploy smoke taxonomy-stable --- .../plan.md | 2 +- .../verification.md | 18 +++++++++- .../deployment/scripts/deploy-docs.sh | 13 +++++-- .../deployment/scripts/smoke-docs.sh | 7 ++-- .../scripts/test-deploy-docs-rollback.sh | 34 ++++++++++++++++--- 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/docs/increments/active/2026-07-29-public-docs-coauthoring/plan.md b/docs/increments/active/2026-07-29-public-docs-coauthoring/plan.md index b597cf8d..a0f8d50a 100644 --- a/docs/increments/active/2026-07-29-public-docs-coauthoring/plan.md +++ b/docs/increments/active/2026-07-29-public-docs-coauthoring/plan.md @@ -11,7 +11,7 @@ English/Vietnamese pair. Taxonomy-only work is a separate structural PR. - [x] Create the durable page register in `apps/docs/AUTHORING.md`. - [x] Transfer unfinished content follow-ups from the completed portal increment. -- [ ] Merge the program foundation and taxonomy migration. +- [x] Merge the program foundation and taxonomy migration. ## Taxonomy Migration diff --git a/docs/increments/active/2026-07-29-public-docs-coauthoring/verification.md b/docs/increments/active/2026-07-29-public-docs-coauthoring/verification.md index 35da16ef..b25617bb 100644 --- a/docs/increments/active/2026-07-29-public-docs-coauthoring/verification.md +++ b/docs/increments/active/2026-07-29-public-docs-coauthoring/verification.md @@ -23,4 +23,20 @@ required version remains the merge authority. ## Delivery -Pending PR review, merge, immutable build, deployment, and live verification. +- PR #134 merged to `main` as + `e2a376358048b85d465532e4f3f8a4bfddeac138`. +- PR CI run `30464083979` and main CI run `30464387882` passed, including the + Node 24 public-docs job and aggregate CI Gate. +- Immutable image build, scan, release recording, and publication passed in run + `30464628816`. +- Initial deploy run `30464858925` started a healthy candidate, then safely + restored `fb1c176b9503a0692a0781b0fa924ac7334e58d3`. The deployment smoke still + expected the retired `/docs/overview` root, and rollback incorrectly compared + the restored old image with the candidate manifest. +- The follow-up repair makes smoke checks taxonomy-stable and limits the + candidate-manifest publication audit to the candidate. Forced-canary rollback + now proves the previous image is checked without applying the candidate + manifest to it. + +Pending repair PR, immutable rebuild, successful deployment, and live +verification. diff --git a/infrastructure/deployment/scripts/deploy-docs.sh b/infrastructure/deployment/scripts/deploy-docs.sh index d251a33f..aaf389d5 100755 --- a/infrastructure/deployment/scripts/deploy-docs.sh +++ b/infrastructure/deployment/scripts/deploy-docs.sh @@ -12,6 +12,7 @@ compose_file="${ORGMEMORY_DOCS_COMPOSE_FILE:-$repo_root/infrastructure/deploymen environment_file="${ORGMEMORY_DOCS_ENV_FILE:-$repo_root/.env.docs.production}" runtime_root="${ORGMEMORY_DOCS_RUNTIME_ROOT:-/apps/orgmemory-runtime/docs}" smoke_script="${ORGMEMORY_DOCS_SMOKE_SCRIPT:-$repo_root/infrastructure/deployment/scripts/smoke-docs.sh}" +publication_verifier="${ORGMEMORY_DOCS_PUBLICATION_VERIFIER:-$repo_root/infrastructure/deployment/scripts/verify-docs-publication.py}" lock_file="$runtime_root/deploy.lock" release_stamp="$(date -u +%Y%m%dT%H%M%SZ)" release_directory="$runtime_root/releases/$release_stamp" @@ -98,16 +99,20 @@ replace_image_reference() { run_smoke() { local public_url + local verify_current_publication="${1:-true}" ORGMEMORY_REPO_ROOT="$repo_root" \ ORGMEMORY_DOCS_COMPOSE_FILE="$compose_file" \ ORGMEMORY_DOCS_ENV_FILE="$environment_file" \ "$smoke_script" - if [[ "${ORGMEMORY_DOCS_REQUIRE_PUBLIC_SMOKE:-false}" == "true" ]]; then + if [[ + "${ORGMEMORY_DOCS_REQUIRE_PUBLIC_SMOKE:-false}" == "true" && + "$verify_current_publication" == "true" + ]]; then public_url="${ORGMEMORY_DOCS_PUBLIC_URL:-$(read_environment_value "$environment_file" ORGMEMORY_DOCS_PUBLIC_URL)}" python3 \ - "$repo_root/infrastructure/deployment/scripts/verify-docs-publication.py" \ + "$publication_verifier" \ "$public_url" fi } @@ -121,7 +126,9 @@ rollback() { install -m 0600 "$current_environment_file" "$environment_file" "${compose[@]}" pull orgmemory-docs "${compose[@]}" up -d --wait --wait-timeout 60 orgmemory-docs - run_smoke + # The previous image may expose an older taxonomy. Verify its stable + # runtime contract, but do not compare it with the candidate manifest. + run_smoke false else install -m 0600 "$previous_environment" "$environment_file" "${compose[@]}" down diff --git a/infrastructure/deployment/scripts/smoke-docs.sh b/infrastructure/deployment/scripts/smoke-docs.sh index 4da7f16d..d32f8089 100755 --- a/infrastructure/deployment/scripts/smoke-docs.sh +++ b/infrastructure/deployment/scripts/smoke-docs.sh @@ -79,6 +79,7 @@ check_public_route() { check_public_root_redirect() { local result + local expected_prefix result="$( curl --fail --location --silent --show-error \ @@ -88,14 +89,13 @@ check_public_root_redirect() { --write-out '%{http_code} %{url_effective}' \ "${public_url%/}/" )" - [[ "$result" == "200 ${public_url%/}/docs/overview" ]] + expected_prefix="200 ${public_url%/}/docs/" + [[ "$result" == "$expected_prefix"* ]] } wait_for_internal_health for route in \ - "/docs/overview" \ "/docs/architecture-security/system-description" \ - "/docs/developers/api-reference/search-catalog" \ "/api/search?query=OpenFGA" \ "/llms.txt"; do check_internal_route "$route" @@ -109,7 +109,6 @@ if [[ "$require_public_smoke" == "true" ]]; then check_public_root_redirect for route in \ "/docs/architecture-security/system-description" \ - "/docs/developers/api-reference/search-catalog" \ "/api/search?query=OpenFGA" \ "/llms.txt"; do check_public_route "$route" diff --git a/infrastructure/deployment/scripts/test-deploy-docs-rollback.sh b/infrastructure/deployment/scripts/test-deploy-docs-rollback.sh index f597fb03..ffda18ad 100755 --- a/infrastructure/deployment/scripts/test-deploy-docs-rollback.sh +++ b/infrastructure/deployment/scripts/test-deploy-docs-rollback.sh @@ -17,16 +17,19 @@ environment_file="$temporary_root/.env.docs.production" compose_file="$temporary_root/compose.docs.yaml" stub_bin="$temporary_root/bin" smoke_script="$temporary_root/smoke.sh" +publication_verifier="$temporary_root/verify-publication.py" production_smoke_script="$repo_root/infrastructure/deployment/scripts/smoke-docs.sh" docker_log="$temporary_root/docker.log" curl_log="$temporary_root/curl.log" smoke_count="$temporary_root/smoke.count" +verifier_count="$temporary_root/verifier.count" old_sha="1111111111111111111111111111111111111111" candidate_sha="2222222222222222222222222222222222222222" install -d -m 0700 "$runtime_root/releases" "$stub_bin" printf 'ORGMEMORY_DOCS_IMAGE=ghcr.io/kl3init/orgmemory-docs:sha-%s\n' \ "$old_sha" > "$environment_file" +printf 'ORGMEMORY_DOCS_PUBLIC_URL=https://docs.example.test\n' >> "$environment_file" chmod 0600 "$environment_file" install -m 0600 "$environment_file" "$runtime_root/current.env" printf '%s\n' "$old_sha" > "$runtime_root/current-commit" @@ -48,12 +51,21 @@ if [[ -f "$ORGMEMORY_DOCS_TEST_SMOKE_COUNT" ]]; then fi count=$((count + 1)) printf '%s\n' "$count" > "$ORGMEMORY_DOCS_TEST_SMOKE_COUNT" -if [[ "$count" -eq 1 ]]; then - exit 1 -fi SH chmod +x "$smoke_script" +cat > "$publication_verifier" <<'PY' +#!/usr/bin/env python3 +import os +from pathlib import Path + +count_path = Path(os.environ["ORGMEMORY_DOCS_TEST_VERIFIER_COUNT"]) +count = int(count_path.read_text() if count_path.exists() else "0") + 1 +count_path.write_text(f"{count}\n") +raise SystemExit(1) +PY +chmod +x "$publication_verifier" + set +e PATH="$stub_bin:$PATH" \ ORGMEMORY_REPO_ROOT="$repo_root" \ @@ -61,8 +73,11 @@ ORGMEMORY_DOCS_COMPOSE_FILE="$compose_file" \ ORGMEMORY_DOCS_ENV_FILE="$environment_file" \ ORGMEMORY_DOCS_RUNTIME_ROOT="$runtime_root" \ ORGMEMORY_DOCS_SMOKE_SCRIPT="$smoke_script" \ +ORGMEMORY_DOCS_PUBLICATION_VERIFIER="$publication_verifier" \ +ORGMEMORY_DOCS_REQUIRE_PUBLIC_SMOKE=true \ ORGMEMORY_DOCS_TEST_DOCKER_LOG="$docker_log" \ ORGMEMORY_DOCS_TEST_SMOKE_COUNT="$smoke_count" \ +ORGMEMORY_DOCS_TEST_VERIFIER_COUNT="$verifier_count" \ "$deploy_script" "$candidate_sha" status="$?" set -e @@ -76,6 +91,7 @@ grep -Fxq \ "ORGMEMORY_DOCS_IMAGE=ghcr.io/kl3init/orgmemory-docs:sha-$old_sha" \ "$environment_file" grep -Fxq "2" "$smoke_count" +grep -Fxq "1" "$verifier_count" if grep -Eq \ '(^|[[:space:]])(api|worker|mcp|web|keycloak|postgres)([[:space:]]|$)' \ @@ -95,7 +111,7 @@ set -euo pipefail printf '%s\n' "$*" >> "$ORGMEMORY_DOCS_TEST_CURL_LOG" url="${!#}" if [[ "$url" == "https://docs.example.test/" ]]; then - printf '200 https://docs.example.test/docs/overview' + printf '200 https://docs.example.test/docs/getting-started' else printf '200' fi @@ -118,11 +134,19 @@ ORGMEMORY_DOCS_TEST_CURL_LOG="$curl_log" \ ORGMEMORY_DOCS_TEST_DOCKER_LOG="$docker_log" \ "$production_smoke_script" -grep -Fq 'http://127.0.0.1:3000/docs/overview' "$docker_log" +grep -Fq \ + 'http://127.0.0.1:3000/docs/architecture-security/system-description' \ + "$docker_log" if grep -Eq 'http://127\.0\.0\.1:3000/$' "$docker_log"; then printf 'Internal smoke still treats the redirecting root as a document.\n' >&2 exit 1 fi +if grep -Eq \ + 'http://127\.0\.0\.1:3000/docs/(overview|developers/api-reference)' \ + "$docker_log"; then + printf 'Internal smoke still depends on the retired taxonomy.\n' >&2 + exit 1 +fi grep -Fq -- '--location' "$curl_log" grep -Fq 'https://docs.example.test/' "$curl_log"