7Read-only registry projection helpers.
11Expose typed reader libraries for queue history, plan lifecycle, plan
12inspection, registry status, and actor identity.
16- Read current-state and operation-log projections without mutating state.
17- Decode canonical JSON payloads into typed dataclass records.
18- Keep SQL limited to SELECT statements.
30- Reader functions never call ``execute_domain_command``.
31- Missing plan rows return ``None`` for explicit plan views.
32- Unknown actor lookups raise ``UnknownActorError``.
36- json (payload decoding)
37- oc_diagnostics (structured debug logging via _dbg)
38- oc_chat.registry.dataclasses (typed read models)
39- oc_chat.registry.errors (typed unknown-actor error)
40- oc_chat.registry.api (Registry facade whose backend connection the readers query)
42from __future__
import annotations
45from typing
import Iterable, Mapping
47from oc_diagnostics
import _dbg
62_dbg(
"OC_CHAT.MAIN",
"module",
"loaded", 4)
64QUEUE_HISTORY_TYPES = {
71 "migrate.import.queue_entry",
76 """Return typed queue history events for ``plan_id``."""
78 placeholders =
", ".join(
"?" for _
in QUEUE_HISTORY_TYPES)
81 "SELECT ts, operation_type, args_json, state_version, actor_slot, "
82 "actor_type, related_plan_id, related_round FROM operation_log "
83 f
"WHERE related_plan_id = ? AND operation_type IN ({placeholders}) "
84 "ORDER BY state_version"
87 rows = conn.execute(sql, (plan_id, *sorted(QUEUE_HISTORY_TYPES))).fetchall()
91 operation_type=str(row[
"operation_type"]),
93 state_version=int(row[
"state_version"]),
94 actor_slot=str(row[
"actor_slot"]),
95 actor_type=str(row[
"actor_type"]),
96 related_plan_id=row[
"related_plan_id"],
97 related_round=row[
"related_round"],
98 is_migration_synthetic=str(row[
"operation_type"]).startswith(
"migrate."),
105 """Return typed status and assignment events for ``plan_id``."""
108 status_rows = conn.execute(
110 "SELECT plan_id, from_status, to_status, actor_slot, source, "
111 "created_at, note FROM plan_status_events "
112 "WHERE plan_id = ? ORDER BY created_at, id",
115 op_rows = conn.execute(
117 "SELECT ts, operation_type, args_json, state_version FROM operation_log "
118 "WHERE related_plan_id = ? AND operation_type = 'plan.assign' "
119 "ORDER BY state_version",
125 ts=str(row[
"created_at"]),
126 plan_id=str(row[
"plan_id"]),
127 from_status=row[
"from_status"],
128 to_status=str(row[
"to_status"]),
129 actor_slot=row[
"actor_slot"],
130 source=row[
"source"],
133 for row
in status_rows
135 assignment_events: list[PlanAssignmentEvent] = []
137 payload =
_payload(row[
"args_json"])
138 if row[
"operation_type"] ==
"plan.assign":
139 assignment_events.append(
142 plan_id=str(payload[
"plan_id"]),
146 state_version=int(row[
"state_version"]),
151 status_events=tuple(status_events),
152 assignment_events=tuple(assignment_events),
156def show_plan(registry: Registry, plan_id: str) -> PlanView |
None:
157 """Return the current projected plan row, or ``None`` if absent."""
162 "SELECT plan_id, plan_number, title, status, assigned_slot, "
163 "queue_position, branch, worktree, body_path, body_sha256 "
164 "FROM plans WHERE plan_id = ?",
170 plan_id=str(row[
"plan_id"]),
171 plan_number=int(row[
"plan_number"]),
172 title=str(row[
"title"]),
173 status=str(row[
"status"]),
174 assigned_slot=row[
"assigned_slot"],
175 queue_position=row[
"queue_position"],
176 branch=row[
"branch"],
177 worktree=row[
"worktree"],
178 body_path=str(row[
"body_path"]),
179 body_sha256=row[
"body_sha256"],
184 """Return compact registry status counters and active runtime rows."""
188 str(row[
"status"]): int(row[
"count"])
189 for row
in conn.execute(
191 "SELECT status, COUNT(*) AS count FROM plans GROUP BY status"
196 for row
in conn.execute(
198 "SELECT round_no, status, cleanup_status, orchestrator_slot "
199 "FROM rounds WHERE status IN ('open', 'closing', 'committed') "
203 active_leases = tuple(
205 for row
in conn.execute(
207 "SELECT id, holder_slot, lease_expires_at, last_heartbeat_at "
208 "FROM leases WHERE holder_slot IS NOT NULL ORDER BY id"
211 state_row = conn.execute(
213 "SELECT id, orchestrator_slot, handover_status, ready_to_handover, "
214 "updated_at, updated_by FROM orchestration_state WHERE id = 1"
217 plan_counts=plan_counts,
218 open_rounds=open_rounds,
219 active_leases=active_leases,
220 orchestration_state=
None if state_row
is None else _row_dict(state_row),
224def whoami(registry: Registry, actor_slot: str) -> ActorView:
225 """Return current actor metadata for ``actor_slot``."""
230 "SELECT slot, slot_kind, identity_kind, model_class, "
231 "orchestrator_eligible, active, provider, profile "
232 "FROM agents WHERE slot = ?",
238 slot=str(row[
"slot"]),
239 slot_kind=str(row[
"slot_kind"]),
240 identity_kind=str(row[
"identity_kind"]),
241 model_class=str(row[
"model_class"]),
242 orchestrator_eligible=bool(row[
"orchestrator_eligible"]),
243 active=bool(row[
"active"]),
244 provider=row[
"provider"],
245 profile=row[
"profile"],
250 connect = getattr(registry.backend,
"connect",
None)
252 raise TypeError(
"registry backend does not expose read connections")
256def _payload(value: object) -> Mapping[str, object]:
259 payload = json.loads(str(value))
260 if not isinstance(payload, dict):
266 keys: Iterable[str] = row.keys()
267 return {key: row[key]
for key
in keys}
271 return None if value
is None else str(value)
275 return None if value
is None else int(value)
PlanView|None show_plan(Registry registry, str plan_id)
PlanTimeline plan_lifecycle(Registry registry, str plan_id)
object _connect(Registry registry)
Mapping[str, object] _payload(object value)
CurrentStatus current_status(Registry registry)
list[QueueEvent] queue_history(Registry registry, str plan_id)
ActorView whoami(Registry registry, str actor_slot)
str|None _optional_str(object value)
int|None _optional_int(object value)
dict[str, object] _row_dict(object row)