# Journal management over HTTP

**Status:** primary binding of the 2026-09-11 management surface.

`ulab-journal serve --management-listen 127.0.0.1:8093` binds the independently
configured management listener. The operations listener defaults to port 8092.
The management address precedence is `--management-listen`, then
`ULAB_JOURNAL_MANAGEMENT_LISTEN`, then `127.0.0.1:8093`.
Both listeners must bind before the service reports readiness. Failure of either
listener ends the service; shutdown drains both before closing durable storage.

Routes below are native listener paths. ULab deployment mounts management at
`/api/management` and operations at `/api/operations`, stripping each prefix
before forwarding to its selected listener. These external paths follow the
[family contract](../../../ulab-standard/MANAGEMENT.md).

Every response, including method and route errors, carries:

```text
Ulab-Service: journal
Ulab-Surface: management
Ulab-Contract: 2026-09-11
```

| Operation | Method and route | Success |
|---|---|---|
| `livez` | `GET /livez` | 200; standard Health, empty checks |
| `health` | `GET /healthz` | 200; standard Health, store and identity checks |
| `describe` | `GET /describe` | 200; ManagementDescribe |
| `describe_file` | `GET /describe/{file}` | 200; listed contract bytes |

All requests accept no body and no query parameters. Invalid request shape
returns 400 `invalid`; a wrong method returns 405 `invalid` with `Allow: GET`.
Unknown paths, including every `/v1` journal operation, return 404 `not_found`.
Readiness returns 503 with the same health envelope if a dependency check fails.
Unexpected failure returns 500 `internal`.

Health uses the [standard operational envelope](../../../ulab-standard/OPERATIONS.md):
`status`, `service`, `contract`, `build`, UTC `time`, `checks`, and optional
`identity.journal_instance_id`. Liveness remains 200 even when the store fails.

Describe contains `service: journal`, `surface: management`, this contract date,
build identity, HTTP binding prefix `/`, management operations and refusals,
the served file inventory, and optional instance identity. It never advertises
the journal operations as management operations.

`GET /describe/{file}` serves only the names in its own description:
`SURFACE.md`, `HTTP.md`, `operations.json`, `openapi.json`, and
`schema/<Type>.schema.json`. Files are embedded at build time. Markdown uses
`text/markdown; charset=utf-8`; JSON uses `application/json`. No host file path
is read. The operations listener's existing neutral introspection routes remain
backwards compatible and continue describing the operations contract.

The separate SDK constructor is `ulabjournal.NewManagement(endpoint)`.
CLI commands `management-health`, `management-livez` and `management-describe`
use `--management-server`, then `ULAB_JOURNAL_MANAGEMENT_SERVER`, then
`http://127.0.0.1:8093`. There is no fallback to the operations endpoint.
