Files
esh-pfi-infrastructure/stacks/muninn-gate
vh 8a824f85a3 docs(muninn-gate): Dockerfile comment — dispatch pin now 0.1.5, SHA-tag note
Gate rebuilt off vh/muninn-gate main (bc04c4c) for the muninn-dispatch
0.1.4->0.1.5 bump (concept_schema/concept_schema_source row fields). Gate
version unchanged at 0.0.14; note to also tag the image with the source SHA
for traceability, and that the pin is authoritative in pyproject.
2026-08-01 17:27:14 -07:00
..

muninn-gate

WG-internal HTTP front door for the Muninn ingestion queue (Worldtree #377). Path-addressed submit, list/status, cancel/retry, watcher-liveness health. Upstream: vh/muninn-gate (no Dockerfile there — this stack owns containerization).

Where it runs

corviduo-dev (10.250.50.152), co-located with the worldtree-personal muninn watcher (worldtree-personal-worldtree-muninn-1). infra-ops-managed stack, separate from the worldtree CI/CD compose. Bind: 10.250.50.152:8090, network_mode: host.

Key wiring (why it's shaped this way)

  • ingestion_root: /data/state/ingestion — the worldtree-personal_worldtree-state volume, mounted at /data/state. Byte-identical path to the watcher's view; the dispatch records absolute paths and both processes read each other's. Acceptance: /healthwatcher.running: true proves this byte-identity (gate is reading the heartbeat the watcher writes). no_heartbeat with the watcher up = root mismatch.
  • user: "1000:1000" — the ingestion dir is vh:vh 0755; the gate must run as uid 1000 to write the queue (non-root, least-privilege). Overrides the image user.
  • staging/mnt/muninn-staging/mimir-inbox, same absolute path bound :ro in BOTH the gate and the watcher (worldtree-dev's b162). Currently a LOCAL placeholder dir; becomes the shared mount when mimir-inbox (the writer) lands. No gate-side check can tell a real share from an empty dir (docker fabricates a missing bind source) — the guard is operational: confirm the host mount exists before wiring/ repointing a bind. Repoint needs a restart (config is read once at boot).
  • health probe uses /ping, not /health/health is always-200 by design (watcher-down is report content, not a status code), so it must never be the liveness probe or it would restart the wrong container.

Config (single-writer, infra-ops)

Real config with bearer-key secrets lives on the server at /opt/docker/conf/muninn-gate/muninn-gate.yaml (1000:1000, 0600, gitignored). Redacted schema: conf/muninn-gate.example.yaml. Schema is CLOSED — any unknown field is a boot failure. Keys are flat-scope (read | submit | control, no inheritance); name is the non-secret submitted_by identity.

Build + deploy

Image builds out-of-band — the Gitea read token (for muninn-dispatch==0.1.4 from the internal index) rides as a BuildKit secret, never a layer:

DOCKER_BUILDKIT=1 docker build --secret id=gitea_pw,src=<gitea-read-token> -t muninn-gate:0.0.14 .
docker compose up -d          # after installing the config to /opt/docker/conf/muninn-gate/

Status

Booted + healthy 2026-07-31; /ping + /health (watcher:running:true, ingestion_root_writable:true) verified. SUBMIT deferred — returns not_found against the placeholder staging until the real shared mount + mimir-inbox writer exist; then repoint + the one-file path-agreement probe + the real acceptance run.