feat: reconcile legacy message identities
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / pytest-smoke (push) Failing after 2s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0230c-b06c-7641-808a-e191b6d1da49
This commit is contained in:
tegwick 2026-08-23 11:59:52 +02:00
parent ab936a1e98
commit ed3feed310
13 changed files with 693 additions and 10 deletions

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import argparse
import json
import uuid
from importlib.resources import files
from pathlib import Path
from typing import Sequence
@ -44,6 +45,30 @@ def build_parser(settings: RuntimeSettings | None = None) -> argparse.ArgumentPa
migration_export.add_argument("--source-revision")
migration_export.add_argument("--output", type=Path, required=True)
message_alias = commands.add_parser(
"message-alias",
help="Manage explicit historical message identity aliases",
)
message_alias_commands = message_alias.add_subparsers(
dest="message_alias_command",
required=True,
)
message_alias_register = message_alias_commands.add_parser(
"register",
help="Bind one exact historical reference to an existing canonical message",
)
message_alias_register.add_argument("--alias", required=True)
message_alias_register.add_argument("--message-id", type=uuid.UUID, required=True)
message_alias_register.add_argument("--source", required=True)
message_alias_register.add_argument("--reason", required=True)
message_alias_register.add_argument("--created-by", required=True)
message_alias_register.add_argument("--database-url", default=resolved.database_url)
message_alias_register.add_argument(
"--confirm",
action="store_true",
help="Confirm the attributable database write",
)
conformance = commands.add_parser(
"conformance",
help="Run the implemented Tier 2/3 profile against an HTTP runtime",
@ -71,6 +96,8 @@ def main(argv: Sequence[str] | None = None) -> int:
return 0
if args.command == "migration":
return _run_migration(args)
if args.command == "message-alias":
return _run_message_alias(args)
if args.command == "conformance":
return _run_conformance(args.base_url, args.timeout, args.as_json)
raise AssertionError(f"Unhandled command {args.command}")
@ -147,5 +174,57 @@ def _run_migration(args: argparse.Namespace) -> int:
return 0 if report.get("ok", True) else 1
def _run_message_alias(args: argparse.Namespace) -> int:
import asyncio
from dataclasses import asdict
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
from hub_core.message_identity import MessageIdentityError, register_message_alias
if args.message_alias_command != "register":
raise AssertionError(f"Unhandled message alias command {args.message_alias_command}")
if not args.confirm:
raise SystemExit("message-alias register requires --confirm")
if not args.database_url:
raise SystemExit(
"message-alias register requires --database-url or HUB_CORE_DATABASE_URL"
)
async def run() -> dict:
engine = create_async_engine(_async_database_url(args.database_url))
sessions = async_sessionmaker(engine, expire_on_commit=False)
try:
async with sessions() as session:
result = await register_message_alias(
session,
alias=args.alias,
message_id=args.message_id,
source=args.source,
reason=args.reason,
created_by=args.created_by,
)
report = asdict(result)
report["message_id"] = str(result.message_id)
report["ok"] = True
return report
finally:
await engine.dispose()
try:
report = asyncio.run(run())
except MessageIdentityError as exc:
print(json.dumps({"ok": False, "error": str(exc)}, sort_keys=True))
return 1
print(json.dumps(report, indent=2, sort_keys=True))
return 0
def _sync_database_url(database_url: str) -> str:
return database_url.replace("postgresql+asyncpg://", "postgresql+psycopg2://")
def _async_database_url(database_url: str) -> str:
if database_url.startswith("postgresql://"):
return database_url.replace("postgresql://", "postgresql+asyncpg://", 1)
return database_url.replace("postgresql+psycopg2://", "postgresql+asyncpg://", 1)