feat: reconcile legacy message identities
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a0230c-b06c-7641-808a-e191b6d1da49
This commit is contained in:
parent
ab936a1e98
commit
ed3feed310
13 changed files with 693 additions and 10 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue