The registry backend: the queue's operations over the registry's own.
Purpose
-------
Plan 258 P3. The queue has one operation set and two backends. This is
the one oc_chat plugs in, and it lives on the REGISTRY side on purpose:
signing, audit and checkpoints already live here, so the queue inherits
them instead of growing a second copy. It implements the same
:class:`~oc_chat.core.work_queue.QueueBackend` protocol over the four
typed operations that ``registry/domain.py`` already exposes --
``queue_enqueue``, ``queue_move``, ``queue_dequeue``, ``queue_complete``
-- and writes nothing else: every mutation is one operation-log row with
``related_plan_id`` set, and the registry's own projection updates the
``plans`` table.
The import direction is registry -> dispatch, which is the permitted
one and the one ``registry/mirror_observer.py`` already takes. Nothing
in the dispatch layer imports this module.
**The vocabulary mismatch, named rather than papered over.** The
registry's operations are slot-shaped and reason-closed; the contract's
are lane-shaped and reason-free. Three things do not fit, and each is
handled in the open:
``lane`` does not map onto ``slot``
MEASURED against a temporary registry, not assumed: ``plans``
declares ``assigned_slot TEXT REFERENCES agents(slot)`` and
``PRAGMA foreign_keys`` is on, so a free-text slot is refused with
``sqlite3.IntegrityError: FOREIGN KEY constraint failed``. The
adapter therefore takes ONE registered slot at construction and
refuses a work item whose ``lane`` names anything else, by name.
No roster was invented to make the mapping work.
``instance`` and the contract's own reason have no column
The queue payloads are fixed and adding a field is a registry
change this plan does not make. They ride in ``command``, the
operation log's free-text provenance column, in a deterministic
form this module also parses back.
``complete`` needs a round and a merge commit
``queue_complete`` requires ``round_no`` and ``merge_commit_sha``.
They are taken as keyword arguments -- which the file backend
accepts and ignores -- rather than smuggled through ``reason``,
because a round number and a sha packed into free text would be a
parser in disguise.
Responsibilities
----------------
- :class:`RegistryQueueBackend` -- the six contract operations.
- :data:`ENQUEUE_REASON` / :data:`DEQUEUE_REASON_DEFAULT` -- the two
closed-set members this adapter maps onto, pinned as constants so the
witness can assert them.
- :class:`LaneIsNotASlotError`, :class:`MissingRegistryArgumentError`,
:class:`UnknownPlanRowError`, :class:`UnsupportedItemKindError` --
the adapter's own named refusals, all under the contract's
:class:`~oc_chat.core.work_queue.QueueBackendError`.
Diagnostics
-----------
Domain: OC_CHAT.MAIN
Levels:
L2 - lifecycle events (an operation emitted)
L3 - semantic details (a mapping, a refusal)
L4 - deep tracing (module load)
Contracts
---------
- This module MUTATES only through ``registry.domain``: no SQL write,
no direct table update. Its reads are SELECTs through
``registry.readers`` and one connection for the ``plans`` projection.
- ``status()`` takes the pending ORDER from the ``plans`` table's
``assigned_slot`` / ``queue_position`` projection -- that projection
is what the registry maintains -- and the PHASE of each item from its
latest queue operation in the log, because the projection models
pending and not-pending and cannot by itself tell "in progress" from
"completed" from "never queued".
- ``kind`` other than ``"plan"`` is refused BY NAME: ``related_plan_id``
is plan-shaped, which the design note ยง5 names as the seam a second
kind will find.
- Nothing here is edited in ``registry/domain.py``,
``registry/backends/**`` or ``registry/cli/**``; this adapter is the
only registry-side file plan 258 adds.
Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
- oc_orchestrator.work_queue (the contract; moved there by plan 271)
- oc_chat.registry.api (the Registry facade)
- oc_chat.registry.domain (the four typed queue operations)
- oc_chat.registry.readers (the queue history reader)