feat(orchestrator): CeremonyOrchestrator + Chronicle.Consumer stubs
CeremonyOrchestrator: GenServer providing a PubSub broadcast interface for ceremony status changes. LiveView subscribes to these broadcasts for real-time updates. A K8s CRD watcher will feed events into this in a future sprint; for now the init log makes the stub state explicit. Chronicle.Consumer: stub for the Ops DB projector that will consume Chronicle events and hydrate the Ecto tables. Projector design (idempotent, checkpointed, catch-up on restart) per DESIGN-OPS-DB-CHAIN-OF-CUSTODY-0001 §2.5. Both modules document the orchestrator/engine distinction: guildhall orchestrates, substrate decides. Both are now supervised by their respective application trees (Guildhall.Orchestrator.Supervisor, Guildhall.Chronicle.Supervisor). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Tyler J King <tking@guildhouse.dev>
This commit is contained in:
parent
69297f1ac0
commit
48a7495ef5
4 changed files with 77 additions and 14 deletions
|
|
@ -1,19 +1,13 @@
|
|||
defmodule Guildhall.Chronicle.Application do
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
@impl true
|
||||
def start(_type, _args) do
|
||||
children = [
|
||||
# Starts a worker by calling: Guildhall.Chronicle.Worker.start_link(arg)
|
||||
# {Guildhall.Chronicle.Worker, arg}
|
||||
Guildhall.Chronicle.Consumer
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: Guildhall.Chronicle.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
|
|
|
|||
26
apps/guildhall_chronicle/lib/guildhall/chronicle/consumer.ex
Normal file
26
apps/guildhall_chronicle/lib/guildhall/chronicle/consumer.ex
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
defmodule Guildhall.Chronicle.Consumer do
|
||||
@moduledoc """
|
||||
Consumes Chronicle events and projects them into the Ops DB.
|
||||
|
||||
See DESIGN-OPS-DB-CHAIN-OF-CUSTODY-0001 §2.5 for the projector
|
||||
design — idempotent insert, checkpoint recovery, catch-up on
|
||||
restart, backpressure handling.
|
||||
|
||||
Stub — the transport (gRPC vs NATS vs Kafka) and the Chronicle
|
||||
event schema are not yet finalized. This module will subscribe
|
||||
to the chosen transport and call into the Ops DB repo for each
|
||||
event, updating `projector_checkpoint` after a successful batch.
|
||||
"""
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
def start_link(opts \\ []) do
|
||||
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_opts) do
|
||||
Logger.info("Chronicle.Consumer started (stub — no transport configured)")
|
||||
{:ok, %{last_entry_id: nil}}
|
||||
end
|
||||
end
|
||||
|
|
@ -1,19 +1,13 @@
|
|||
defmodule Guildhall.Orchestrator.Application do
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
@impl true
|
||||
def start(_type, _args) do
|
||||
children = [
|
||||
# Starts a worker by calling: Guildhall.Orchestrator.Worker.start_link(arg)
|
||||
# {Guildhall.Orchestrator.Worker, arg}
|
||||
Guildhall.Orchestrator.CeremonyOrchestrator
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: Guildhall.Orchestrator.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
defmodule Guildhall.Orchestrator.CeremonyOrchestrator do
|
||||
@moduledoc """
|
||||
Coordinates ceremony workflows by (eventually) watching substrate
|
||||
CeremonyRequest CRDs and notifying witnesses via PubSub.
|
||||
|
||||
Currently a stub — the K8s CRD watcher will be wired in once the
|
||||
`:k8s` package is added and a kubeconfig is available.
|
||||
|
||||
### Orchestrator vs engine
|
||||
|
||||
This module ORCHESTRATES (notifies humans, collects signatures,
|
||||
broadcasts status). The substrate `CeremonyEngine` DECIDES
|
||||
(evaluates Accord conditions, advances the state machine).
|
||||
|
||||
See DESIGN-ORG-OPS-FRAMEWORK-0001 §3.2 for the separation.
|
||||
"""
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
def start_link(opts \\ []) do
|
||||
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Broadcast a ceremony status change to all LiveView subscribers.
|
||||
|
||||
Called by the K8s watcher (future) or manually in tests. Fans
|
||||
out on both the per-ceremony topic and the wildcard topic.
|
||||
"""
|
||||
def broadcast_ceremony_status(ceremony_id, status) do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Guildhall.PubSub,
|
||||
"ceremony:#{ceremony_id}",
|
||||
{:ceremony_status, ceremony_id, status}
|
||||
)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Guildhall.PubSub,
|
||||
"ceremony:*",
|
||||
{:ceremony_status, ceremony_id, status}
|
||||
)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_opts) do
|
||||
Logger.info("CeremonyOrchestrator started (stub — no K8s watcher yet)")
|
||||
{:ok, %{watcher: nil}}
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue