oc_chat
Loading...
Searching...
No Matches
queue.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oc_chat/registry/cli/queue.py
4
5# OCT-LINT: disable=tests_exist reason="Covered by oc_chat/tests/registry/test_domain_queue.py"
6"""
7Registry-native queue commands.
8
9Purpose
10-------
11Expose queue mutation and history commands beneath
12``python -m oc_chat.registry queue``.
13
14Responsibilities
15----------------
16- Parse queue domain command arguments.
17- Resolve the registry and actor slot.
18- Dispatch to the domain API and reader library.
19
20Diagnostics
21-----------
22Domain: OC_CHAT.MAIN
23Levels:
24 L2 - lifecycle events
25 L3 - semantic details
26 L4 - deep tracing
27
28Contracts
29---------
30- Mutating commands emit exactly one operation-log row through the seam.
31- ``history`` is read-only and returns decoded typed events.
32
33Dependencies
34------------
35- oc_diagnostics (structured debug logging via _dbg)
36- oc_chat.registry.backends.sqlite (SQLite backend)
37- oc_chat.registry.discovery (registry path discovery)
38- oc_chat.registry.domain (queue mutation API)
39- oc_chat.registry.readers (queue history reader)
40- oc_chat.registry (Registry facade for queue mutations and the history reader)
41"""
42from __future__ import annotations
43
44import argparse
45import json
46from typing import Callable
47
48from oc_diagnostics import _dbg
49
50from oc_chat.registry import Registry
51from oc_chat.registry.backends.sqlite import SQLiteBackend
52from oc_chat.registry.discovery import discover_registry_location
53from oc_chat.registry.domain import (
54 queue_complete,
55 queue_dequeue,
56 queue_enqueue,
57 queue_move,
58)
59from oc_chat.registry.readers import queue_history
60
61
62_dbg("OC_CHAT.MAIN", "module", "loaded", 4)
63
64
65def add_queue_subcommands(queue_parser: argparse.ArgumentParser) -> None:
66 """Attach registry-native queue subcommands."""
67
68 queue_parser.set_defaults(handler=_cmd_queue_group, queue_parser=queue_parser)
69 subcommands = queue_parser.add_subparsers(dest="queue_command")
70
71 enqueue = subcommands.add_parser("enqueue", help="Emit queue.enqueue")
72 _add_common(enqueue)
73 enqueue.add_argument("plan_id")
74 enqueue.add_argument("--slot", required=True)
75 enqueue.add_argument("--position", required=True, type=int)
76 enqueue.add_argument(
77 "--reason",
78 required=True,
79 choices=[
80 "initial enqueue",
81 "promoted_from_partial",
82 "restored_from_aborted_round",
83 ],
84 )
85 enqueue.set_defaults(handler=_cmd_enqueue)
86
87 move = subcommands.add_parser("move", help="Emit queue.move")
88 _add_common(move)
89 move.add_argument("plan_id")
90 move.add_argument("--from-slot", required=True)
91 move.add_argument("--to-slot", required=True)
92 move.add_argument("--from-position", required=True, type=int)
93 move.add_argument("--to-position", required=True, type=int)
94 move.add_argument("--reason", required=True)
95 move.set_defaults(handler=_cmd_move)
96
97 dequeue = subcommands.add_parser("dequeue", help="Emit queue.dequeue")
98 _add_common(dequeue)
99 dequeue.add_argument("plan_id")
100 dequeue.add_argument("--slot", required=True)
101 dequeue.add_argument("--position", required=True, type=int)
102 dequeue.add_argument(
103 "--reason",
104 required=True,
105 choices=[
106 "transition_to_failed",
107 "transition_to_integrating",
108 "operator_dequeue",
109 ],
110 )
111 dequeue.set_defaults(handler=_cmd_dequeue)
112
113 complete = subcommands.add_parser("complete", help="Emit queue.complete")
114 _add_common(complete)
115 complete.add_argument("plan_id")
116 complete.add_argument("--round-no", required=True, type=int)
117 complete.add_argument("--merge-commit-sha", required=True)
118 complete.set_defaults(handler=_cmd_complete)
119
120 history = subcommands.add_parser("history", help="Show queue history")
121 history.add_argument("plan_id")
122 history.add_argument("--registry", help="Registry SQLite path.")
123 history.add_argument("--json", action="store_true")
124 history.set_defaults(handler=_cmd_history)
125
126
127def _cmd_queue_group(args: argparse.Namespace) -> int:
128 parser = args.queue_parser
129 parser.print_help()
130 return 1
131
132
133def _cmd_enqueue(args: argparse.Namespace) -> int:
134 return _emit(
135 args,
136 lambda registry, actor_slot: queue_enqueue(
137 registry,
138 plan_id=args.plan_id,
139 slot=args.slot,
140 position=args.position,
141 reason=args.reason,
142 actor_slot=actor_slot,
143 actor_type="human_operator",
144 command="queue enqueue",
145 ),
146 )
147
148
149def _cmd_move(args: argparse.Namespace) -> int:
150 return _emit(
151 args,
152 lambda registry, actor_slot: queue_move(
153 registry,
154 plan_id=args.plan_id,
155 from_slot=args.from_slot,
156 to_slot=args.to_slot,
157 from_position=args.from_position,
158 to_position=args.to_position,
159 reason=args.reason,
160 actor_slot=actor_slot,
161 actor_type="human_operator",
162 command="queue move",
163 ),
164 )
165
166
167def _cmd_dequeue(args: argparse.Namespace) -> int:
168 return _emit(
169 args,
170 lambda registry, actor_slot: queue_dequeue(
171 registry,
172 plan_id=args.plan_id,
173 slot=args.slot,
174 position=args.position,
175 reason=args.reason,
176 actor_slot=actor_slot,
177 actor_type="human_operator",
178 command="queue dequeue",
179 ),
180 )
181
182
183def _cmd_complete(args: argparse.Namespace) -> int:
184 return _emit(
185 args,
186 lambda registry, actor_slot: queue_complete(
187 registry,
188 plan_id=args.plan_id,
189 round_no=args.round_no,
190 merge_commit_sha=args.merge_commit_sha,
191 actor_slot=actor_slot,
192 actor_type="human_operator",
193 command="queue complete",
194 ),
195 )
196
197
198def _cmd_history(args: argparse.Namespace) -> int:
199 registry, _backend = _registry(args.registry)
200 events = queue_history(registry, args.plan_id)
201 if args.json:
202 print(json.dumps([event.__dict__ for event in events], indent=2, sort_keys=True))
203 else:
204 for event in events:
205 print(
206 f"{event.state_version}: {event.operation_type} "
207 f"{dict(event.payload)}"
208 )
209 return 0
210
211
213 args: argparse.Namespace,
214 emit: Callable[[Registry, str], object],
215) -> int:
216 registry, backend = _registry(args.registry)
217 actor_slot = args.actor_slot or backend.active_operator_slot()
218 if actor_slot is None:
219 print("no active operator slot found")
220 return 1
221 row = emit(registry, actor_slot)
222 print(f"operation {getattr(row, 'id')} state_version={getattr(row, 'state_version')}")
223 return 0
224
225
226def _registry(registry_path: str | None) -> tuple[Registry, SQLiteBackend]:
227 location = discover_registry_location(registry_path=registry_path)
228 backend = SQLiteBackend(location.registry_path)
229 return Registry(backend), backend
230
231
232def _add_common(parser: argparse.ArgumentParser) -> None:
233 parser.add_argument("--registry", help="Registry SQLite path.")
234 parser.add_argument("--actor-slot", help="Actor slot. Defaults to active operator.")
None _add_common(argparse.ArgumentParser parser)
Definition queue.py:232
int _cmd_enqueue(argparse.Namespace args)
Definition queue.py:133
int _cmd_dequeue(argparse.Namespace args)
Definition queue.py:167
int _emit(argparse.Namespace args, Callable[[Registry, str], object] emit)
Definition queue.py:215
int _cmd_history(argparse.Namespace args)
Definition queue.py:198
tuple[Registry, SQLiteBackend] _registry(str|None registry_path)
Definition queue.py:226
int _cmd_queue_group(argparse.Namespace args)
Definition queue.py:127
int _cmd_move(argparse.Namespace args)
Definition queue.py:149
None add_queue_subcommands(argparse.ArgumentParser queue_parser)
Definition queue.py:65
int _cmd_complete(argparse.Namespace args)
Definition queue.py:183