oc_chat
Loading...
Searching...
No Matches
hub_manage.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oc_chat/scripts/hub_manage.py
4
5# OCT-LINT: disable=tests_exist reason="Wiring shim; covered by oc_chat/tests/unit/test_272_hub_shims.py"
6"""
7The hub's operator surface — moved to :mod:`oc_orchestrator.hub_manage`.
8
9Purpose
10-------
11Plan 272 P4. The CLI now lives in the standalone ``oc_orchestrator``
12package. This file keeps ``oc_chat.scripts.hub_manage`` working — the
13path the rendered launch brief names at every worker's STEP-0, and the
14one ``MULTI_AGENT_WORKFLOW.md`` and every orchestrator command have
15always spelled — and supplies the two defaults that are oc_chat's and
16not the package's:
17
18- **the program name.** ``--help`` must print exactly what it printed
19 before the split, and ``prog`` is the only line in it that could differ.
20- **the registry log.** The package declares ``--backend registry`` as a
21 plugin point and holds no registry to fill it; oc_chat has one, so this
22 is where the factory is built. ``--backend registry`` therefore behaves
23 byte for byte as it did before the split, and the four lazy registry
24 imports that used to sit inside the package's ``_build_log`` sit here
25 instead — which is precisely the seam the plan-259 receipt modelled as
26 a named ``--cut``.
27
28Unlike the two ``core/`` hub shims this module is NOT a rebinding,
29because it has behaviour of its own: those two defaults. Every other name
30is delegated by :func:`__getattr__`, which is what keeps
31``from oc_chat.scripts.hub_manage import default_hooks`` working for
32``tests/unit/test_259_dispatch_hooks.py`` unedited.
33
34Responsibilities
35----------------
36- :func:`main` — the package's CLI with oc_chat's ``prog`` and factory.
37- :func:`_registry_log` — the registry arm, verbatim from the pre-272
38 module's ``_build_log``.
39- :func:`__getattr__` — every other name, delegated unchanged.
40
41Diagnostics
42-----------
43Domain: OC_CHAT.MAIN
44Levels:
45 L2 - lifecycle events (which log was built)
46 L3 - semantic details
47 L4 - deep tracing (delegated name lookups)
48
49Contracts
50---------
51- Output is byte-identical to the pre-272 module for every sub-command,
52 and so are the rows a registry-mode round trip lands in the registry.
53- The registry imports stay LAZY, inside the factory: the file backend is
54 the default, and a ``hub_manage asks`` against it must not drag the
55 registry's auth, signing and checkpoint stack into the process.
56- The refusal the registry arm raises is the package's own
57 :class:`~oc_orchestrator.hub_file.CorruptHubLogError`, so ``main``'s
58 handler gives it the same ``backend refused:`` line and exit code 2 it
59 gave before the split.
60- Retirement rule (plan 272 P4): this path stays until an explicit
61 retirement plan retargets the launch brief and the workflow doc. New
62 code names ``oc_orchestrator.hub_manage`` directly.
63
64Dependencies
65------------
66- oc_diagnostics (structured debug logging via _dbg)
67- oc_orchestrator.hub_manage (the moved module this path wraps)
68- oc_orchestrator.hub_file (the refusal class the factory raises)
69- oc_chat.registry (lazy; Registry, which wraps the storage the registry hub log writes to)
70- oc_chat.registry.backends.sqlite (lazy; SQLiteBackend, the registry storage and its active operator slot)
71- oc_chat.registry.discovery (lazy; discover_registry_location, which finds the registry file)
72- oc_chat.registry.hub_log (lazy; RegistryHubLog, the registry-backed hub log the factory returns)
73"""
74
75from __future__ import annotations
76
77import argparse
78import sys
79from typing import Any
80
81from oc_diagnostics import _dbg
82
83from oc_orchestrator import hub_manage as _moved
84from oc_orchestrator.hub_file import CorruptHubLogError
85
86#: The program name this path has always printed in ``--help``.
87PROG = "python -m oc_chat.scripts.hub_manage"
88
89_dbg("OC_CHAT.MAIN", "module", "hub_manage shim -> oc_orchestrator.hub_manage", 4)
90
91
92def __getattr__(name: str) -> Any:
93 """Delegate every name this shim does not define to the moved module."""
94 return getattr(_moved, name)
95
96
97def _registry_log(args: argparse.Namespace) -> Any:
98 """Build the registry-backed hub log (plan 272 P2's consumer factory).
99
100 Lifted verbatim from the registry arm of the pre-272
101 ``hub_manage._build_log``. The package declares the seam and names no
102 registry; this is the consumer that fills it, so the four imports the
103 plan-259 receipt cut as a named edge now live on oc_chat's side of
104 the split, where they always belonged.
105
106 Raises:
107 CorruptHubLogError: SYSTEM_ERROR (L1 for the caller) — the
108 registry could not be opened, or it holds no active operator
109 slot, so there is no actor to attribute the messages to.
110 """
111 func = "_registry_log"
112 # Imported here, not at module scope: the file backend is the
113 # default, and a `hub_manage asks` against it must not drag the
114 # registry's auth, signing and checkpoint stack into the process.
115 from oc_chat.registry import Registry
116 from oc_chat.registry.backends.sqlite import SQLiteBackend
117 from oc_chat.registry.discovery import discover_registry_location
118 from oc_chat.registry.hub_log import RegistryHubLog
119
120 try:
121 location = discover_registry_location(registry_path=args.registry)
122 storage = SQLiteBackend(location.registry_path)
123 actor_slot = args.actor_slot or storage.active_operator_slot()
124 except Exception as exc: # noqa: BLE001 - the foreign storage stack, one arm
125 # Building the registry log can fail in that package's OWN
126 # exception vocabulary -- a sqlite3.OperationalError for an absent
127 # file, a discovery error for an unmarked tree. Every one of them
128 # means the same thing to this CLI, "the backend refused", and it
129 # gets the backend exit code with the original message kept.
130 raise CorruptHubLogError(
131 f"the registry backend could not be opened: {type(exc).__name__}: {exc}"
132 ) from exc
133 if actor_slot is None:
134 raise CorruptHubLogError("no active operator slot found in the registry")
135 _dbg("OC_CHAT.MAIN", func, f"registry log as {actor_slot}", 2)
136 return RegistryHubLog(Registry(storage), actor_slot=actor_slot)
137
138
139def main(argv: list[str] | None = None) -> int:
140 """Run one sub-command with oc_chat's program name and registry log."""
141 return _moved.main(argv, prog=PROG, log_factory=_registry_log)
142
143
144if __name__ == "__main__":
145 sys.exit(main())
Any _registry_log(argparse.Namespace args)
Definition hub_manage.py:97
Any __getattr__(str name)
Definition hub_manage.py:92