checkpoint: complete recoverable V2 pre-separation baseline

Complete the selective V2 checkpoint with its minimal AgentBus, object-storage, replay persistence, and validated-workbench shared dependency closure.
This commit is contained in:
鲨鱼辣椒 committed 2026-08-20 17:09:00 +08:00
1 parent 7330ac853b
commit 694c4317a3
627 files changed
+130467 -885

No files matched your search

+42 -106
View File
@@ -1,116 +1,52 @@
#!/usr/bin/env bash
# Validate the contracts-v1 PostgreSQL migration without touching any schema
# other than th_hotel_booking. This script is safe by default: it refuses a
# schema containing objects outside the booking_contract_* namespace.
# Run the opt-in CP4 PostgreSQL infrastructure smoke through the same Flyway
# and Spring repository code used by the application. The JUnit gate validates
# the approved legacy V001 coexistence shape before any write, migrates V1-V14,
# restarts independent application contexts, verifies durable claim/fencing plus
# the controlled-Provider Layer 3 path, and removes all synthetic source-rooted rows.
set -euo pipefail
readonly BOOKING_SCHEMA='th_hotel_booking'
readonly MIGRATION_FILES=(
'server/src/main/resources/db/booking-postgresql/migration/V1__booking_contracts_v1.sql'
'server/src/main/resources/db/booking-postgresql/migration/V2__booking_sender_mapping_direction.sql'
required_variables=(
TH_HOTEL_BOOKING_PG_URL
TH_HOTEL_BOOKING_PG_USERNAME
TH_HOTEL_BOOKING_PG_PASSWORD
TH_HOTEL_BOOKING_PG_SMOKE_DATABASE
)
for variable_name in "${required_variables[@]}"; do
if [[ -z "${!variable_name:-}" ]]; then
echo "${variable_name} is required through the deployment Secret environment." >&2
exit 64
fi
done
database_url="${BOOKING_PG_VERIFY_URL:-${TH_HOTEL_BOOKING_PG_URL:-}}"
if [[ -z "${database_url}" ]]; then
echo 'BOOKING_PG_VERIFY_URL (or TH_HOTEL_BOOKING_PG_URL) is required.' >&2
exit 64
if [[ "${TH_HOTEL_BOOKING_PG_SMOKE_APPROVED:-false}" != 'true' ]]; then
echo 'Set TH_HOTEL_BOOKING_PG_SMOKE_APPROVED=true only for an explicitly approved non-production database.' >&2
exit 65
fi
if [[ "${BOOKING_PG_VERIFY_SCHEMA:-${BOOKING_SCHEMA}}" != "${BOOKING_SCHEMA}" ]]; then
echo "Only ${BOOKING_SCHEMA} may be verified by this script." >&2
exit 64
fi
for migration_file in "${MIGRATION_FILES[@]}"; do
if [[ ! -f "${migration_file}" ]]; then
echo "Canonical booking migration was not found: ${migration_file}" >&2
case "${TH_HOTEL_BOOKING_PG_URL}" in
jdbc:postgresql://*) ;;
postgresql://*)
export TH_HOTEL_BOOKING_PG_URL="jdbc:${TH_HOTEL_BOOKING_PG_URL}"
;;
postgres://*)
export TH_HOTEL_BOOKING_PG_URL="jdbc:postgresql://${TH_HOTEL_BOOKING_PG_URL#postgres://}"
;;
*)
echo 'TH_HOTEL_BOOKING_PG_URL must be a PostgreSQL JDBC or PostgreSQL connection URL.' >&2
exit 64
;;
esac
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repository_root="$(cd "${script_dir}/.." && pwd)"
for migration_version in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do
if ! compgen -G "${repository_root}/server/src/main/resources/db/booking-postgresql/migration/V${migration_version}__*.sql" >/dev/null; then
echo "Canonical Booking PostgreSQL V${migration_version} migration is missing." >&2
exit 66
fi
done
if ! command -v psql >/dev/null 2>&1; then
echo 'psql is required to run PostgreSQL migration verification.' >&2
exit 69
fi
psql_query() {
psql -X -qAt -v ON_ERROR_STOP=1 -d "${database_url}" -c "$1"
}
schema_exists="$(psql_query "SELECT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = '${BOOKING_SCHEMA}');")"
if [[ "${schema_exists}" == 't' ]]; then
unexpected_objects="$(psql_query "
SELECT count(*)
FROM pg_class relation
JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace
WHERE namespace.nspname = '${BOOKING_SCHEMA}'
AND relation.relkind IN ('r', 'p', 'S', 'v', 'm')
AND relation.relname NOT LIKE 'booking_contract_%'
AND relation.relname <> 'flyway_schema_history';")"
if [[ "${unexpected_objects}" != '0' ]]; then
echo "Refusing to use ${BOOKING_SCHEMA}: it contains ${unexpected_objects} non-contract object(s)." >&2
exit 65
fi
fi
# Count user objects outside the project schema. The migration is allowed to
# create only th_hotel_booking objects; a count change is a hard failure.
other_objects_before="$(psql_query "
SELECT count(*)
FROM pg_class relation
JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace
WHERE namespace.nspname NOT IN ('pg_catalog', 'information_schema', '${BOOKING_SCHEMA}')
AND namespace.nspname NOT LIKE 'pg_toast%'
AND relation.relkind IN ('r', 'p', 'S', 'v', 'm');")"
psql -X -q --single-transaction -v ON_ERROR_STOP=1 -d "${database_url}" \
-f "${MIGRATION_FILES[0]}" \
-f "${MIGRATION_FILES[1]}"
other_objects_after="$(psql_query "
SELECT count(*)
FROM pg_class relation
JOIN pg_namespace namespace ON namespace.oid = relation.relnamespace
WHERE namespace.nspname NOT IN ('pg_catalog', 'information_schema', '${BOOKING_SCHEMA}')
AND namespace.nspname NOT LIKE 'pg_toast%'
AND relation.relkind IN ('r', 'p', 'S', 'v', 'm');")"
if [[ "${other_objects_before}" != "${other_objects_after}" ]]; then
echo 'PostgreSQL migration verification detected a non-booking schema object change.' >&2
exit 70
fi
required_tables=(
booking_contract_source_message
booking_contract_source_attachment
booking_contract_processing_run
booking_contract_processing_attempt
booking_contract_evidence_reference
booking_contract_artifact
booking_contract_parsed_fact
booking_contract_candidate_target
booking_contract_confirmation_action
booking_contract_channel_profile
booking_contract_sender_mapping
booking_contract_rate_code_mapping
)
for table_name in "${required_tables[@]}"; do
present="$(psql_query "SELECT to_regclass('${BOOKING_SCHEMA}.${table_name}') IS NOT NULL;")"
if [[ "${present}" != 't' ]]; then
echo "Missing required booking table: ${BOOKING_SCHEMA}.${table_name}" >&2
exit 71
fi
done
cross_schema_fk_count="$(psql_query "
SELECT count(*)
FROM pg_constraint constraint
JOIN pg_class source_relation ON source_relation.oid = constraint.conrelid
JOIN pg_namespace source_namespace ON source_namespace.oid = source_relation.relnamespace
JOIN pg_class target_relation ON target_relation.oid = constraint.confrelid
JOIN pg_namespace target_namespace ON target_namespace.oid = target_relation.relnamespace
WHERE constraint.contype = 'f'
AND (source_namespace.nspname = '${BOOKING_SCHEMA}' OR target_namespace.nspname = '${BOOKING_SCHEMA}')
AND source_namespace.nspname <> target_namespace.nspname;")"
if [[ "${cross_schema_fk_count}" != '0' ]]; then
echo 'Booking PostgreSQL migration created or found a cross-schema foreign key.' >&2
exit 72
fi
echo "Booking PostgreSQL migration verified in ${BOOKING_SCHEMA}; other schema object count unchanged (${other_objects_after})."
export TH_HOTEL_BOOKING_PG_SMOKE_ENABLED=true
cd "${repository_root}/server"
exec ./mvnw -Dtest=BookingPostgresCp4InfrastructureSmokeTest test